Simple TCP mocking tool for replaying tcpdump or Wireshark captured service or client traffic.
If you like this project, please give it a star ⭐! This helps the project be more visible, gain relevance and encourages us to invest more effort in new features.
This project is inspired in other tools like WireMock, mountebank and MockTCPServer, but provides following features that are partially supported by listed tools:
- TCP mocking support, with async messages sent (i.e: allows sending welcome messages which are not supported by mountebank).
- Load mocking specification from tcpdump
.pcap
or Wireshark.json
dump files and provides a reduced.yaml
format for easy versioning. - Allows to easily run the mock embedded in Java projects for easy testing
- Allows both mocking servers and clients.
Take into consideration that this tool is very simple, and only replays TCP traffic that has previously been recorded, so if user (or server) interacts with the tool in unexpected ways, then the mock will not answer until next expected packet is received. For more complex scenarios consider using one of previously mentioned tools.
This tool (as previously listed ones) is particularly useful to implement integration tests without the hassle of flaky connections, or complex environment setup or restrictions (VPN, quotas, etc).
Note: If you use .pcap
, since Wiresham uses pcap4j for .pcap
files support, you need to install libpcap or winpcap as detailed in pcap4j website.
The general use case for the tool takes following steps:
-
User captures traffic with tcpdump (with something like
tcpdump port 23 -w ~/traffic.pcap
) or Wireshark between a client application and a service. -
If traffic has been captured with Wireshark then store the captured traffic, filtering with proper condition for service port, in a
.json
file (File -> Export Packet Dissections -> As JSON...) -
At this point user might follow three potential courses:
-
Start Wiresham in standalone mode with stored
.pcap
or.json
and connect to it with the client application to reproduce previously stored traffic.E.g.:
java -jar wiresham-standalone.jar -p 2324 -a 0.0.0.0 wireshark-dump.json
Latest version of wiresham-standalone.jar can be downloaded from maven central.
A similar example for a tcpdump traffic:
E.g.:
java -jar wiresham-standalone.jar -p 2324 -a 0.0.0.0 traffic.pcap
Run
java -jar wiresham-standalone.jar -h
to get usage instructions and help. -
Same as previous one but start Wiresham in standalong mode to emulate a client application (instead of a service application):
E.g.:
java -jar wiresham-standalone.jar -t 0.0.0.0:23 -a 0.0.0.0 wireshark-dump.json
Note that the only difference with previous example is the use of
-t
to specify target server address instead of the-p
option to specify the local port.-
Convert the tcpdump or Wireshark dump to a reduced
.yaml
file (an example file can be found in simple.yaml), optionally manually tune it (response times or binary packets), add it to the project repository and implement tests using VirtualTcpService class or VirtualTcpClient class.To convert a script run something like
java -jar wiresham-standalone.jar -d reduced-dump.yml -a 0.0.0.0 wireshark-dump.json
.To add Wiresham as dependency in maven project include in
pom.xml
the dependency:<dependency> <groupId>us.abstracta</groupId> <artifactId>wiresham</artifactId> <version>0.1</version> </dependency>
Check what is the latest version in releases
Check VirtualTcpServiceTest and VirtualTcpClientTest for simple and raw examples on how to use the classes.
-
There are some scenarios where we need to mock several services under the same domain but differing from port. For such scenarios multiple port support was added. Here there is a flow example on how a YAML would look:
- !server {data: FFFF, delayMillis: 10, port: 2324}
- !client {data: FFFF}
- !server {data: FFFF, port: 2325}
- !client {data: FFFF}
- !server {data: FFFF}
Important considerations:
- Connections can be established at any time
- Dump is read sequentially. Meaning that any packet received out of order will be ignored (parallelism not yet supported)
- When a port is defined, subsequent packets until another port is defined will use the mentioned port without having to explicitly define it (as shown in the example)
- Wireshark dumps and tcpdumps are parsed using multiple port when providing endpoint address using
-a
flagNote: if port is provided alonside with the address E.g: 0.0.0.0:23 only the specified port will be parsed otherwise, all involved ports will be part of the flow.
- Client mode also supported
When modularization is important for your flow include is the designated tool for the job, take a look to this example:
- !server { data: 48656C6C6F, port: 23 }
- !client { data: 48656C6C6F2C2049276D204A6F686E }
- !include { id: "innerFlow" }
- !server { data: 427965204A6F686E }
- !include { id: "2" }
---
id: "innerFlow"
steps:
- !server { data: 48656C6C6F204A6F686E, port: 24 }
- !client { data: 427965 }
---
- !server { data: 427965204A6F686E, port: 25 }
- Flows are separated by
---
as standardized by YAML syntax to separate documents - It is possible to call a flow using either the id of the flow or the index of the flow (one indexed)
- Connections opened inside an include will remain there. Therefore consequent packets (after the include) will use a connection defined in main flow.
Looking at the example, the packet between includes will use the connection established in port 23.
Since packet dissections are in JSON schema we can take advantage of using jq.
The filter to use can be applied using:
- Using jq playground (online version of jq). Here there is an example.
- Using jq cli.
jq '<filter-here>' dissection-packets.json
Filter: . |= map(select((.["_source"].layers.tcp["tcp.srcport"] == "PORT_NUMBER") or (.["_source"].layers.tcp["tcp.dstport"] == "PORT_NUMBER")))
PORT_NUMBER needs to be replaced by the port we want to filter.
In short, this filter is going to exclude all packets that don't interact with the PORT_NUMBER we want.
In case you want to build this project from scratch, it is required JDK8+ and maven 3.3+.
Then just run mvn clean install
and the library (and standalone version) will be built and installed in the local maven repository.
To release the project, define the version to be released by checking included changes since last release and following semantic versioning.
Then, create a release (including v
as prefix of the version, e.g. v0.1
), this will trigger a GitHub Actions workflow which will publish the jars to maven central repository (and make it general available to be used as maven dependency projects) in around 10 mins and can be found in maven central search after up to 2 hours.