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>