You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/02/27 14:24:05 UTC

[plc4x] branch develop updated: - Implemented a tool to replay wireshark dumps

This is an automated email from the ASF dual-hosted git repository.

cdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/develop by this push:
     new 986fab3  - Implemented a tool to replay wireshark dumps
986fab3 is described below

commit 986fab315563ec6459c5286e1fa7d4766287536f
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Thu Feb 27 15:23:56 2020 +0100

    - Implemented a tool to replay wireshark dumps
---
 plc4j/tools/capture-replay/README.adoc             |  38 +++++++
 plc4j/tools/capture-replay/pom.xml                 |  88 ++++++++++++++++
 .../java/utils/capturereplay/CaptureReplay.java    | 113 +++++++++++++++++++++
 .../plc4x/java/utils/capturereplay/CliOptions.java | 105 +++++++++++++++++++
 plc4j/tools/pom.xml                                |   1 +
 pom.xml                                            |   6 ++
 6 files changed, 351 insertions(+)

diff --git a/plc4j/tools/capture-replay/README.adoc b/plc4j/tools/capture-replay/README.adoc
new file mode 100644
index 0000000..447b8e1
--- /dev/null
+++ b/plc4j/tools/capture-replay/README.adoc
@@ -0,0 +1,38 @@
+//
+//  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.
+//
+
+== Capture Replay Tool
+
+Some times it is difficult to track down problems where they occur.
+
+Especially when it comes to passive mode drivers, problems sometimes are difficult to track down.
+
+However with this tool it's easy to to this work by simply recording a WireShark recording of the network traffic and then replaying this from another device.
+
+In my setup I use an ordinary Raspberry PI to replay a previously recorded capture and then to work on the passive mode drivers as if you were connected to the real thing.
+
+=== Usage
+
+In order to replay a previously recorded network capture, you need:
+
+- The `PCAPNG` capture itself
+- The name of the network device (like shown by `ifconfig` or `ipconfig` (on Windows))
+- An optional replay speed (if omitted a value of `1` is assumed which is real-time)
+
+Run the application like this:
+
+    java -jar plc4j-capture-replay-0.7.0-SNAPSHOT.jar
\ No newline at end of file
diff --git a/plc4j/tools/capture-replay/pom.xml b/plc4j/tools/capture-replay/pom.xml
new file mode 100644
index 0000000..3c8410c
--- /dev/null
+++ b/plc4j/tools/capture-replay/pom.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+  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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.plc4x</groupId>
+    <artifactId>plc4j-tools</artifactId>
+    <version>0.7.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>plc4j-capture-replay</artifactId>
+
+  <name>PLC4J: Tools: Capture Replay</name>
+  <description>Tool for actively sending out packets captured via WireShark.</description>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>3.2.1</version>
+        <executions>
+          <execution>
+            <id>generate-uber-jar</id>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+            <configuration>
+              <transformers combine.children="append">
+                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                  <mainClass>org.apache.plc4x.java.utils.capturereplay.CaptureReplay</mainClass>
+                </transformer>
+              </transformers>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <configuration>
+          <usedDependencies>
+            <usedDependency>org.pcap4j:pcap4j-packetfactory-static</usedDependency>
+          </usedDependencies>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>commons-cli</groupId>
+      <artifactId>commons-cli</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.pcap4j</groupId>
+      <artifactId>pcap4j-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.pcap4j</groupId>
+      <artifactId>pcap4j-packetfactory-static</artifactId>
+      <scope>runtime</scope>
+    </dependency>
+  </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/plc4j/tools/capture-replay/src/main/java/org/apache/plc4x/java/utils/capturereplay/CaptureReplay.java b/plc4j/tools/capture-replay/src/main/java/org/apache/plc4x/java/utils/capturereplay/CaptureReplay.java
new file mode 100644
index 0000000..ffe1371
--- /dev/null
+++ b/plc4j/tools/capture-replay/src/main/java/org/apache/plc4x/java/utils/capturereplay/CaptureReplay.java
@@ -0,0 +1,113 @@
+/*
+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.plc4x.java.utils.capturereplay;
+
+import org.pcap4j.core.*;
+import org.pcap4j.packet.Packet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.sql.Timestamp;
+import java.util.concurrent.TimeUnit;
+
+public class CaptureReplay {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(CaptureReplay.class);
+
+    private final File inputFile;
+    private final String outputDevice;
+    private final float replaySpeed;
+
+    public CaptureReplay(CliOptions options) {
+        inputFile = options.getInputFile();
+        if (!(inputFile.exists() && inputFile.isFile())) {
+            throw new IllegalArgumentException("Could not open file " + inputFile.getPath());
+        }
+        outputDevice = options.getOutputDevice();
+        replaySpeed = options.getReplaySpeed();
+    }
+
+    public void run() throws PcapNativeException {
+        PcapHandle readHandle = Pcaps.openOffline(inputFile.getAbsolutePath(), PcapHandle.TimestampPrecision.NANO);
+
+        PcapNetworkInterface sendDevice = Pcaps.getDevByName(outputDevice);
+        PcapHandle sendHandle = sendDevice.openLive(65536, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, 100);
+
+        // Start a thread that processes the callbacks from the raw socket and simply
+        // forwards the bytes read to the buffer.
+        Thread loopThread = new Thread(() -> {
+            try {
+                readHandle.loop(-1, new PacketListener() {
+                    private Timestamp lastPacketTime = null;
+
+                    @Override
+                    public void gotPacket(Packet packet) {
+                        Timestamp curPacketTime = readHandle.getTimestamp();
+
+                        // Only enable the throttling if it is not disabled.
+                        // If last-time is not null, wait for the given number of nano-seconds.
+                        if((replaySpeed <= 0) && (lastPacketTime != null)) {
+                            int numMicrosecondsSleep = (int)
+                                ((curPacketTime.getNanos() - lastPacketTime.getNanos()) * replaySpeed);
+                            nanoSecondSleep(numMicrosecondsSleep);
+                        }
+
+                        // Send the packet to the output device ...
+                        try {
+                            sendHandle.sendPacket(packet);
+                        } catch (PcapNativeException | NotOpenException e) {
+                            LOGGER.error("Error sending packet", e);
+                        }
+
+                        // Remember the timestamp of the current packet.
+                        lastPacketTime = curPacketTime;
+                    }
+                });
+            } catch (PcapNativeException | NotOpenException e) {
+                LOGGER.error("PCAP sending loop thread died!", e);
+            } catch (InterruptedException e) {
+                LOGGER.warn("PCAP sending loop thread was interrupted (hopefully intentionally)", e);
+                Thread.currentThread().interrupt();
+            }
+        });
+        loopThread.start();
+    }
+
+    private void nanoSecondSleep(long numNanos) {
+        try {
+            TimeUnit.NANOSECONDS.sleep(numNanos);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        CliOptions options = CliOptions.fromArgs(args);
+        if (options == null) {
+            CliOptions.printHelp();
+            // Could not parse.
+            System.exit(1);
+        }
+
+        CaptureReplay replay = new CaptureReplay(options);
+        replay.run();
+    }
+
+}
diff --git a/plc4j/tools/capture-replay/src/main/java/org/apache/plc4x/java/utils/capturereplay/CliOptions.java b/plc4j/tools/capture-replay/src/main/java/org/apache/plc4x/java/utils/capturereplay/CliOptions.java
new file mode 100644
index 0000000..2267051
--- /dev/null
+++ b/plc4j/tools/capture-replay/src/main/java/org/apache/plc4x/java/utils/capturereplay/CliOptions.java
@@ -0,0 +1,105 @@
+/*
+ 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.plc4x.java.utils.capturereplay;
+
+import org.apache.commons.cli.*;
+
+import java.io.File;
+
+public class CliOptions {
+
+    private static final String OPTION_INPUT_FILE = "input-file";
+    private static final String OPTION_OUTPUT_DEVICE = "output-device";
+    private static final String OPTION_REPLAY_SPEED = "replay-speed";
+
+    private static Options options;
+
+    private final File inputFile;
+    private final String outputDevice;
+    private final float replaySpeed;
+
+    public static CliOptions fromArgs(String[] args) {
+        options = new Options();
+        // Required arguments
+        options.addOption(
+            Option.builder()
+                .type(String.class)
+                .longOpt(OPTION_INPUT_FILE)
+                .hasArg()
+                .desc("Path to the PCAP(NG) file.")
+                .required()
+                .build());
+        options.addOption(
+            Option.builder()
+                .type(String.class)
+                .longOpt(OPTION_OUTPUT_DEVICE)
+                .hasArgs()
+                .desc("Name of the device that should output the packets")
+                .required()
+                .build());
+        options.addOption(
+            Option.builder()
+                .type(String.class)
+                .longOpt(OPTION_REPLAY_SPEED)
+                .hasArgs()
+                .desc("Replay speed (1 = real time, 0 = as fast as possible, 0.5 = half speed, 2 = double speed")
+                .build());
+
+        CommandLineParser parser = new DefaultParser();
+        CommandLine commandLine;
+        try {
+            commandLine = parser.parse(options, args);
+
+            File inputFile = new File(commandLine.getOptionValue(OPTION_INPUT_FILE));
+            String outputDevice = commandLine.getOptionValue(OPTION_OUTPUT_DEVICE);
+            float replaySpeed = Float.parseFloat(
+                commandLine.hasOption(OPTION_REPLAY_SPEED) ? commandLine.getOptionValue(OPTION_REPLAY_SPEED) : "1");
+
+            return new CliOptions(inputFile, outputDevice, replaySpeed);
+        } catch (ParseException e) {
+            System.err.println(e.getMessage());
+            return null;
+        }
+    }
+
+    public static void printHelp() {
+        HelpFormatter formatter = new HelpFormatter();
+        formatter.printHelp("CaptureReplay", options);
+    }
+
+    public CliOptions(File inputFile, String outputDevice, float replaySpeed) {
+        this.inputFile = inputFile;
+        this.outputDevice = outputDevice;
+        this.replaySpeed = replaySpeed;
+    }
+
+    public File getInputFile() {
+        return inputFile;
+    }
+
+    public String getOutputDevice() {
+        return outputDevice;
+    }
+
+    public float getReplaySpeed() {
+        return replaySpeed;
+    }
+
+}
diff --git a/plc4j/tools/pom.xml b/plc4j/tools/pom.xml
index 66958ed..d3eb5a2 100644
--- a/plc4j/tools/pom.xml
+++ b/plc4j/tools/pom.xml
@@ -34,6 +34,7 @@
   <description>A collection of tools that provide additional services to users.</description>
 
   <modules>
+    <module>capture-replay</module>
     <module>connection-pool</module>
     <module>opm</module>
     <module>scraper</module>
diff --git a/pom.xml b/pom.xml
index 2fa5bef..8ddc855 100644
--- a/pom.xml
+++ b/pom.xml
@@ -115,6 +115,7 @@
     <byte-buddy.version>1.9.10</byte-buddy.version>
     <cmake-version>3.16.0</cmake-version>
     <commons-beanutils.version>1.9.4</commons-beanutils.version>
+    <commons-cli.version>1.4</commons-cli.version>
     <commons-codec.version>1.12</commons-codec.version>
     <commons-collections4.version>4.1</commons-collections4.version>
     <commons-configuration2.version>2.6</commons-configuration2.version>
@@ -279,6 +280,11 @@
         <version>${commons-beanutils.version}</version>
       </dependency>
       <dependency>
+        <groupId>commons-cli</groupId>
+        <artifactId>commons-cli</artifactId>
+        <version>${commons-cli.version}</version>
+      </dependency>
+      <dependency>
         <groupId>commons-codec</groupId>
         <artifactId>commons-codec</artifactId>
         <version>${commons-codec.version}</version>