forked from cramer/pcapmirror
Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e3097eec3a | |||
| a2c0ad8bfb | |||
| e39c130a69 | |||
| a128da1328 | |||
| 99fbd6f600 | |||
| 5e595b0ae7 | |||
| 5ee45654f2 | |||
| 1da4934e59 | |||
| 0897fa1755 | |||
| 1233bf5ede | |||
| 038a6de68e | |||
| 39a8b7c016 | |||
| 4356a49271 | |||
| c6caf71afd | |||
| c2166bb7ec | |||
| eb41f3b6e4 | |||
| a17b8379bb | |||
| 1b98555ed3 | |||
| c640aa6f22 | |||
| c6584cde87 | |||
| 4300e30f04 | |||
| 0fdd4a9783 | |||
| 49173fef25 | |||
| 8e586dade0 | |||
| c7e16616a1 | |||
| 9d91fda7e1 | |||
| 3c007c3fcc | |||
| 8ff71daa36 | |||
| 3a078c5ba2 | |||
| 232fe98fd9 | |||
| 9e30e4e7aa | |||
| 2f4c086eba | |||
| e76fb7e61f | |||
| 269488b60d | |||
| b07369b5b0 | |||
| 8e01a2823c | |||
| d86c3829f5 | |||
| 1471e39e50 | |||
| 0ffa2b82bf | |||
| f3604f7390 | |||
| 0a71915fd8 | |||
| f207c5bdc2 | |||
| 8869da41b5 | |||
| f1c0985c99 | |||
| bc23a64b46 | |||
| b334754945 | |||
| faece01978 | |||
| 02c69f2936 | |||
| c2475e04f9 | |||
| ba55d4d958 | |||
| b176c8edef | |||
| 1d67a904b9 | |||
| 646a888e84 | |||
| aa86180054 | |||
| 94266b53a9 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,7 @@
|
|||||||
*~
|
*~
|
||||||
*.o
|
*.o
|
||||||
|
*.gz
|
||||||
pcapmirror
|
pcapmirror
|
||||||
debian/debhelper-build-stamp
|
debian/debhelper-build-stamp
|
||||||
debian/pcapmirror.substvars
|
debian/pcapmirror.substvars
|
||||||
|
debian/files
|
||||||
|
|||||||
190
.gitlab-ci.yml
190
.gitlab-ci.yml
@@ -1,18 +1,21 @@
|
|||||||
|
|
||||||
stages:
|
stages:
|
||||||
- build
|
- build
|
||||||
|
- publish
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
DEBIAN_FRONTEND: noninteractive
|
DEBIAN_FRONTEND: noninteractive
|
||||||
|
VERSION: 0.5
|
||||||
|
|
||||||
build-bookworm:
|
build-bookworm:
|
||||||
stage: build
|
stage: build
|
||||||
|
needs: []
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
tags:
|
tags:
|
||||||
- bookworm
|
- bookworm
|
||||||
script:
|
script:
|
||||||
- tar -czf ../pcapmirror_0.2.orig.tar.gz --exclude=debian .
|
- tar -czf ../pcapmirror_$VERSION.orig.tar.gz --exclude=debian .
|
||||||
- apt-get update && apt-get install -y libpcap-dev
|
- apt-get update && apt-get install -y libpcap-dev
|
||||||
- dpkg-buildpackage -uc -us
|
- dpkg-buildpackage -uc -us
|
||||||
- mkdir -p build
|
- mkdir -p build
|
||||||
@@ -20,21 +23,32 @@ build-bookworm:
|
|||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- build/*.deb
|
- build
|
||||||
- build/*.dsc
|
|
||||||
- build/*.tar.xz
|
publish-bookworm:
|
||||||
- build/*.changes
|
stage: publish
|
||||||
- build/*.buildinfo
|
needs:
|
||||||
- build/*.diff.gz
|
- build-bookworm
|
||||||
|
dependencies:
|
||||||
|
- build-bookworm
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
tags:
|
||||||
|
- bookworm
|
||||||
|
script:
|
||||||
|
- apt-get update && apt-get install -y curl
|
||||||
|
- ls -la build
|
||||||
|
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/pcapmirror_$VERSION-1_amd64.deb ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/bookworm/pcapmirror_$VERSION-1_amd64.deb'
|
||||||
|
|
||||||
build-sid:
|
build-sid:
|
||||||
stage: build
|
stage: build
|
||||||
|
needs: []
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
tags:
|
tags:
|
||||||
- sid
|
- sid
|
||||||
script:
|
script:
|
||||||
- tar -czf ../pcapmirror_0.2.orig.tar.gz --exclude=debian .
|
- tar -czf ../pcapmirror_$VERSION.orig.tar.gz --exclude=debian .
|
||||||
- apt-get update && apt-get install -y libpcap-dev
|
- apt-get update && apt-get install -y libpcap-dev
|
||||||
- dpkg-buildpackage -uc -us
|
- dpkg-buildpackage -uc -us
|
||||||
- mkdir -p build
|
- mkdir -p build
|
||||||
@@ -42,9 +56,157 @@ build-sid:
|
|||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- build/*.deb
|
- build
|
||||||
- build/*.dsc
|
|
||||||
- build/*.tar.xz
|
publish-sid:
|
||||||
- build/*.changes
|
stage: publish
|
||||||
- build/*.buildinfo
|
needs:
|
||||||
- build/*.diff.gz
|
- build-sid
|
||||||
|
dependencies:
|
||||||
|
- build-sid
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
tags:
|
||||||
|
- bookworm
|
||||||
|
script:
|
||||||
|
- apt-get update && apt-get install -y curl
|
||||||
|
- ls -la build
|
||||||
|
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/pcapmirror_$VERSION-1_amd64.deb ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/sid/pcapmirror_$VERSION-1_amd64.deb'
|
||||||
|
|
||||||
|
build-rocky9:
|
||||||
|
stage: build
|
||||||
|
needs: []
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
tags:
|
||||||
|
- rocky9
|
||||||
|
script:
|
||||||
|
- dnf install -y libpcap-devel
|
||||||
|
- mkdir -p /root/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
||||||
|
- tar -czf /root/rpmbuild/SOURCES/pcapmirror-v$VERSION.tar.gz --exclude=debian --exclude=.git .
|
||||||
|
- cp -r * /root/rpmbuild/BUILD
|
||||||
|
- rpmbuild -ba pcapmirror.spec
|
||||||
|
- mkdir -p build
|
||||||
|
- mv /root/rpmbuild/RPMS/x86_64/pcapmirror*.* build/
|
||||||
|
- mv /root/rpmbuild/SRPMS/pcapmirror*.* build/
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- build
|
||||||
|
|
||||||
|
publish-rocky9:
|
||||||
|
stage: publish
|
||||||
|
needs:
|
||||||
|
- build-rocky9
|
||||||
|
dependencies:
|
||||||
|
- build-rocky9
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
tags:
|
||||||
|
- bookworm
|
||||||
|
script:
|
||||||
|
- apt-get update && apt-get install -y curl
|
||||||
|
- ls -la build
|
||||||
|
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/pcapmirror-$VERSION-*.el9.x86_64.rpm ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/rockylinux9/pcapmirror-$VERSION-1.el8.x86_64.rpm'
|
||||||
|
|
||||||
|
build-rocky8:
|
||||||
|
stage: build
|
||||||
|
needs: []
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
tags:
|
||||||
|
- rocky8
|
||||||
|
script:
|
||||||
|
- dnf install -y libpcap-devel
|
||||||
|
- mkdir -p /root/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
||||||
|
- tar -czf /root/rpmbuild/SOURCES/pcapmirror-v$VERSION.tar.gz --exclude=debian --exclude=.git .
|
||||||
|
- cp -r * /root/rpmbuild/BUILD
|
||||||
|
- rpmbuild -ba pcapmirror.spec
|
||||||
|
- mkdir -p build
|
||||||
|
- mv /root/rpmbuild/RPMS/x86_64/pcapmirror*.* build/
|
||||||
|
- mv /root/rpmbuild/SRPMS/pcapmirror*.* build/
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- build
|
||||||
|
|
||||||
|
publish-rocky8:
|
||||||
|
stage: publish
|
||||||
|
needs:
|
||||||
|
- build-rocky8
|
||||||
|
dependencies:
|
||||||
|
- build-rocky8
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
tags:
|
||||||
|
- bookworm
|
||||||
|
script:
|
||||||
|
- apt-get update && apt-get install -y curl
|
||||||
|
- ls -la build
|
||||||
|
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/pcapmirror-$VERSION-*.el8.x86_64.rpm ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/rockylinux8/pcapmirror-$VERSION-1.el8.x86_64.rpm'
|
||||||
|
|
||||||
|
build-pios12:
|
||||||
|
stage: build
|
||||||
|
needs: []
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
tags:
|
||||||
|
- pios12
|
||||||
|
script:
|
||||||
|
- tar -czf ../pcapmirror_$VERSION.orig.tar.gz --exclude=debian .
|
||||||
|
- apt-get update && apt-get install -y libpcap-dev
|
||||||
|
- dpkg-buildpackage -uc -us
|
||||||
|
- mkdir -p build
|
||||||
|
- mv ../pcapmirror*.* build/
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- build
|
||||||
|
|
||||||
|
publish-pios12:
|
||||||
|
stage: publish
|
||||||
|
needs:
|
||||||
|
- build-pios12
|
||||||
|
dependencies:
|
||||||
|
- build-pios12
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
tags:
|
||||||
|
- bookworm
|
||||||
|
script:
|
||||||
|
- apt-get update && apt-get install -y curl
|
||||||
|
- ls -la build
|
||||||
|
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/pcapmirror_$VERSION-1_armhf.deb ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/bookworm/pcapmirror_$VERSION-1_armhf.deb'
|
||||||
|
|
||||||
|
build-pios12-64:
|
||||||
|
stage: build
|
||||||
|
needs: []
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
tags:
|
||||||
|
- pios12-64
|
||||||
|
script:
|
||||||
|
- tar -czf ../pcapmirror_$VERSION.orig.tar.gz --exclude=debian .
|
||||||
|
- apt-get update && apt-get install -y libpcap-dev
|
||||||
|
- dpkg-buildpackage -uc -us
|
||||||
|
- mkdir -p build
|
||||||
|
- mv ../pcapmirror*.* build/
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- build
|
||||||
|
|
||||||
|
publish-pios12-64:
|
||||||
|
stage: publish
|
||||||
|
needs:
|
||||||
|
- build-pios12-64
|
||||||
|
dependencies:
|
||||||
|
- build-pios12-64
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
tags:
|
||||||
|
- bookworm
|
||||||
|
script:
|
||||||
|
- apt-get update && apt-get install -y curl
|
||||||
|
- ls -la build
|
||||||
|
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/pcapmirror_$VERSION-1_arm64.deb ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/bookworm/pcapmirror_$VERSION-1_arm64.deb'
|
||||||
|
|||||||
10
Makefile
10
Makefile
@@ -22,7 +22,7 @@ TARGET = pcapmirror
|
|||||||
PREFIX = /usr
|
PREFIX = /usr
|
||||||
|
|
||||||
# Default rule
|
# Default rule
|
||||||
all: $(TARGET)
|
all: $(TARGET) man
|
||||||
|
|
||||||
# Create executable
|
# Create executable
|
||||||
$(TARGET): $(OBJS)
|
$(TARGET): $(OBJS)
|
||||||
@@ -32,6 +32,9 @@ $(TARGET): $(OBJS)
|
|||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
man:
|
||||||
|
gzip -9 -c pcapmirror.8 > pcapmirror.8.gz
|
||||||
|
|
||||||
# Clean up object files and executable
|
# Clean up object files and executable
|
||||||
clean:
|
clean:
|
||||||
rm -f -f $(OBJS) $(TARGET)
|
rm -f -f $(OBJS) $(TARGET)
|
||||||
@@ -39,11 +42,14 @@ clean:
|
|||||||
# Install the executable
|
# Install the executable
|
||||||
install: $(TARGET)
|
install: $(TARGET)
|
||||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||||
install -D $(TARGET) $(DESTDIR)$(PREFIX)/bin/$(TARGET)
|
install -D $(TARGET) $(DESTDIR)$(PREFIX)/bin/$(TARGET)
|
||||||
|
install -D $(TARGET).8 $(DESTDIR)$(PREFIX)/share/man/man8/$(TARGET).8
|
||||||
|
|
||||||
|
|
||||||
# Uninstall the executable
|
# Uninstall the executable
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f $(TARGET) $(DESTDIR)$(PREFIX)/bin/$(TARGET)
|
rm -f $(TARGET) $(DESTDIR)$(PREFIX)/bin/$(TARGET)
|
||||||
|
rm -f $(TARGET).8.gz $(DESTDIR)$(PREFIX)/share/man/man8/$(TARGET).8.gz
|
||||||
|
|
||||||
# Run the executable (example)
|
# Run the executable (example)
|
||||||
run: $(TARGET)
|
run: $(TARGET)
|
||||||
|
|||||||
40
README.md
40
README.md
@@ -1,4 +1,7 @@
|
|||||||
|
|
||||||
# pcapmirror
|
# pcapmirror
|
||||||
|

|
||||||
|
|
||||||
pcapmirror is a command-line tool for capturing network traffic and mirroring it to a remote destination using [TZSP encapsulation](https://en.wikipedia.org/wiki/TZSP). It leverages the `libpcap` library for packet capture and provides options for filtering traffic based on BPF syntax. This tool is useful for network monitoring, intrusion detection, and remote packet analysis.
|
pcapmirror is a command-line tool for capturing network traffic and mirroring it to a remote destination using [TZSP encapsulation](https://en.wikipedia.org/wiki/TZSP). It leverages the `libpcap` library for packet capture and provides options for filtering traffic based on BPF syntax. This tool is useful for network monitoring, intrusion detection, and remote packet analysis.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -9,12 +12,16 @@ pcapmirror [options]
|
|||||||
|
|
||||||
### Options:
|
### Options:
|
||||||
|
|
||||||
* -i <interface>: Specify the capture interface (e.g., eth0).
|
* -i <interface> Specify the capture interface
|
||||||
* -f <filter>: Specify the capture filter in BPF syntax (e.g., tcp port 80).
|
* -f <filter> Specify the capture filter (BPF syntax)
|
||||||
* -r <ip_address>: Specify the destination IP address (required).
|
* -r <host/ipv4/ipv6> Specify the destination host (required)
|
||||||
* -p <port>: Specify the destination port (default: 37008).
|
* -p <port> Specify the destination port (default: 37008)
|
||||||
* -v: Enable verbose mode (prints packet information).
|
* -4 Force IPv4 host lookup
|
||||||
* -h: Show this help message.
|
* -6 Force IPv6 host lookup
|
||||||
|
* -l List available network interfaces.
|
||||||
|
* -v Enable verbose mode
|
||||||
|
* -c Count matching packets (overrides verbose mode)
|
||||||
|
* -h Show this help message
|
||||||
|
|
||||||
### Example:
|
### Example:
|
||||||
|
|
||||||
@@ -31,8 +38,25 @@ With this tool, you can mirror traffic directly to a running [Wireshark](https:/
|
|||||||
|
|
||||||
To avoid capturing traffic from your own monitoring machine, configure Wireshark with a capture filter of udp port 37008 or udp dst port 37008. Also, verify that your firewall permits this UDP traffic.
|
To avoid capturing traffic from your own monitoring machine, configure Wireshark with a capture filter of udp port 37008 or udp dst port 37008. Also, verify that your firewall permits this UDP traffic.
|
||||||
|
|
||||||
|
## Original Download Location
|
||||||
|
|
||||||
|
[https://git.freestone.net/cramer/pcapmirror](https://git.freestone.net/cramer/pcapmirror)
|
||||||
|
|
||||||
|
## Packages
|
||||||
|
|
||||||
|
On the original download location you will also find several prebuilt packages.
|
||||||
|
|
||||||
## Compile and Install
|
## Compile and Install
|
||||||
|
|
||||||
|
### Supported Operating Systems
|
||||||
|
Source is tested to build and function on the following operating systems
|
||||||
|
|
||||||
|
* Debian Linux 12 + unstable (sid)
|
||||||
|
* Rocky Linux 8 + 9
|
||||||
|
* PiOS 12 (bookworm)
|
||||||
|
* OpenBSD 7.6
|
||||||
|
* MacOS 15
|
||||||
|
|
||||||
Compile the program:
|
Compile the program:
|
||||||
```bash
|
```bash
|
||||||
make
|
make
|
||||||
@@ -45,7 +69,7 @@ make install
|
|||||||
|
|
||||||
This will copy the pcapmirror executable to bin. You may need to adjust the PREFIX variable in the Makefile if you want to install it to a different location.
|
This will copy the pcapmirror executable to bin. You may need to adjust the PREFIX variable in the Makefile if you want to install it to a different location.
|
||||||
|
|
||||||
Dependencies
|
### Dependencies
|
||||||
libpcap: You need to have libpcap installed on your system. On Debian/Ubuntu systems, you can install it using:
|
libpcap: You need to have libpcap installed on your system. On Debian/Ubuntu systems, you can install it using:
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get install libpcap-dev
|
sudo apt-get install libpcap-dev
|
||||||
@@ -57,7 +81,7 @@ sudo yum install libpcap-devel
|
|||||||
```
|
```
|
||||||
## Build debian package
|
## Build debian package
|
||||||
|
|
||||||
If you have never built a debian pakage you probably need debhelper:
|
If you have never built a debian package you probably need debhelper:
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get install debhelper
|
sudo apt-get install debhelper
|
||||||
```
|
```
|
||||||
|
|||||||
23
debian/changelog
vendored
23
debian/changelog
vendored
@@ -1,3 +1,26 @@
|
|||||||
|
pcapmirror (0.5-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* new option -c to count matching packets (overrides verbose mode)
|
||||||
|
* reworked packet decoder to also decode arp, vlan and qinq packets
|
||||||
|
* well known protocols numbers are now decoded
|
||||||
|
* works now on MacOS and OpenBSD
|
||||||
|
|
||||||
|
-- Matthias Cramer <cramer@freestone.net> Fri, 29 Mar 2025 13:40:00 +0100
|
||||||
|
|
||||||
|
pcapmirror (0.4-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* IPv6 support for remote destination
|
||||||
|
* remote destination can now also be hostname
|
||||||
|
* added option to enforce IPv4 and IPv6 for remote destination
|
||||||
|
|
||||||
|
-- Matthias Cramer <cramer@freestone.net> Fri, 24 Mar 2025 13:40:00 +0100
|
||||||
|
|
||||||
|
pcapmirror (0.3-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* added manpage
|
||||||
|
|
||||||
|
-- Matthias Cramer <cramer@freestone.net> Fri, 21 Mar 2025 16:00:05 +0100
|
||||||
|
|
||||||
pcapmirror (0.2-1) unstable; urgency=medium
|
pcapmirror (0.2-1) unstable; urgency=medium
|
||||||
|
|
||||||
* First Debian package
|
* First Debian package
|
||||||
|
|||||||
3
debian/files
vendored
3
debian/files
vendored
@@ -1,3 +0,0 @@
|
|||||||
pcapmirror-dbgsym_0.2-1_amd64.deb debug optional automatic=yes
|
|
||||||
pcapmirror_0.2-1_amd64.buildinfo net optional
|
|
||||||
pcapmirror_0.2-1_amd64.deb net optional
|
|
||||||
3
debian/install
vendored
3
debian/install
vendored
@@ -1 +1,2 @@
|
|||||||
pcapmirror /usr/bin
|
pcapmirror /usr/bin
|
||||||
|
pcapmirror.8 /usr/share/man/man8
|
||||||
BIN
logo/pcapmirror_logo.png
Normal file
BIN
logo/pcapmirror_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 600 KiB |
BIN
logo/pcapmirror_logo_small.png
Normal file
BIN
logo/pcapmirror_logo_small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
375
main.c
375
main.c
@@ -6,25 +6,24 @@ Copyright (c) 2025, Matthias Cramer, cramer@freestone.net
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <pcap.h>
|
|
||||||
#include <netinet/ip.h>
|
|
||||||
#include <netinet/tcp.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
#define ENABLE_IPV6
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#ifdef ENABLE_IPV6
|
#include <pcap.h>
|
||||||
#include <netinet/ip6.h> // Include for IPv6 header definition
|
#include <netinet/in.h>
|
||||||
#endif
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/ip6.h>
|
||||||
|
#include <net/if_arp.h>
|
||||||
|
#include <netinet/if_ether.h> // For Ethernet and ARP headers
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#define DEFAULT_DEST_PORT 37008 // Default TZSP port
|
#define DEFAULT_DEST_PORT 37008 // Default TZSP port
|
||||||
#define TZSP_ENCAP_LEN 4 // Length of TZSP encapsulation header
|
#define TZSP_ENCAP_LEN 4 // Length of TZSP encapsulation header
|
||||||
#define TZSP_TAGGED_LEN 1 // Length of TZSP tagged field header (type)
|
#define TZSP_TAGGED_LEN 1 // Length of TZSP tagged field header (type)
|
||||||
#define ETHERNET_HEADER_LENGTH 14
|
#define ETHERNET_HEADER_LENGTH 14 // Assuming Ethernet header is 14 bytes
|
||||||
|
|
||||||
// TZSP Header Structure
|
// TZSP Header Structure
|
||||||
struct tzsp_header {
|
struct tzsp_header {
|
||||||
@@ -39,38 +38,118 @@ struct tzsp_tagged {
|
|||||||
unsigned char type; // Tag type
|
unsigned char type; // Tag type
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add this structure for ARP header parsing
|
||||||
|
struct arp_header {
|
||||||
|
uint16_t htype; // Hardware type
|
||||||
|
uint16_t ptype; // Protocol type
|
||||||
|
uint8_t hlen; // Hardware address length
|
||||||
|
uint8_t plen; // Protocol address length
|
||||||
|
uint16_t oper; // Operation (1 = request, 2 = reply)
|
||||||
|
uint8_t sha[6]; // Sender hardware address
|
||||||
|
uint8_t spa[4]; // Sender protocol address
|
||||||
|
uint8_t tha[6]; // Target hardware address
|
||||||
|
uint8_t tpa[4]; // Target protocol address
|
||||||
|
};
|
||||||
|
|
||||||
// Function to check if the system is little-endian
|
// Function to check if the system is little-endian
|
||||||
int is_little_endian() {
|
int is_little_endian() {
|
||||||
volatile unsigned int i=0x01234567;
|
volatile unsigned int i=0x01234567;
|
||||||
return (((unsigned char*)&i)[0] == 0x67);
|
return (((unsigned char*)&i)[0] == 0x67);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void list_interfaces() {
|
||||||
|
pcap_if_t *alldevs;
|
||||||
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
|
if (pcap_findalldevs(&alldevs, errbuf) == -1) {
|
||||||
|
fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("Available network interfaces:\n");
|
||||||
|
for (pcap_if_t *d = alldevs; d != NULL; d = d->next) {
|
||||||
|
printf("%s", d->name);
|
||||||
|
if (d->description) {
|
||||||
|
printf(" (%s)", d->description);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
pcap_freealldevs(alldevs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to lookup protocol name or return protocol number as a string
|
||||||
|
const char *lookup_protocol_name(int protocol) {
|
||||||
|
static char buf[5]; // Buffer to hold protocol number as a string
|
||||||
|
|
||||||
|
switch (protocol) {
|
||||||
|
case 1:
|
||||||
|
return "ICMP";
|
||||||
|
case 2:
|
||||||
|
return "IGMP";
|
||||||
|
case 6:
|
||||||
|
return "TCP";
|
||||||
|
case 17:
|
||||||
|
return "UDP";
|
||||||
|
case 41:
|
||||||
|
return "IPv6";
|
||||||
|
case 47:
|
||||||
|
return "GRE";
|
||||||
|
case 50:
|
||||||
|
return "ESP";
|
||||||
|
case 51:
|
||||||
|
return "AH";
|
||||||
|
case 58:
|
||||||
|
return "ICMPv6";
|
||||||
|
case 89:
|
||||||
|
return "OSPF";
|
||||||
|
case 112:
|
||||||
|
return "VRRP";
|
||||||
|
case 124:
|
||||||
|
return "ISIS";
|
||||||
|
case 132:
|
||||||
|
return "SCTP";
|
||||||
|
default:
|
||||||
|
snprintf(buf, sizeof(buf), "%d", protocol); // Convert protocol number to string
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void print_usage(const char *program_name) {
|
void print_usage(const char *program_name) {
|
||||||
printf("Usage: %s [options]\n", program_name);
|
printf("Usage: %s [options]\n", program_name);
|
||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
printf(" -i <interface> Specify the capture interface\n");
|
printf(" -i <interface> Specify the capture interface\n");
|
||||||
printf(" -f <filter> Specify the capture filter (BPF syntax)\n");
|
printf(" -f <filter> Specify the capture filter (BPF syntax)\n");
|
||||||
printf(" -r <ip_address> Specify the destination IP address (required)\n");
|
printf(" -r <host/ipv4/ipv6> Specify the destination host (required)\n");
|
||||||
printf(" -p <port> Specify the destination port (default: %d)\n", DEFAULT_DEST_PORT);
|
printf(" -p <port> Specify the destination port (default: %d)\n", DEFAULT_DEST_PORT);
|
||||||
printf(" -v Enable verbose mode\n");
|
printf(" -4 Force IPv4 host lookup\n");
|
||||||
printf(" -h Show this help message\n");
|
printf(" -6 Force IPv6 host lookup\n");
|
||||||
|
printf(" -l List available network interfaces\n");
|
||||||
|
printf(" -v Enable verbose mode\n");
|
||||||
|
printf(" -c Count matching packets (overrides verbose mode)\n");
|
||||||
|
printf(" -h Show this help message\n");
|
||||||
printf("Example:\n");
|
printf("Example:\n");
|
||||||
printf(" %s -i eth0 -f 'tcp port 80' -v -r 192.168.1.100 -p 47008\n", program_name);
|
printf(" %s -i eth0 -f 'tcp port 80' -v -r 192.168.1.100 -p 47008\n", program_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
pcap_if_t *alldevs;
|
|
||||||
char errbuf[PCAP_ERRBUF_SIZE];
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
char *filter_exp = "tcp port 8088"; // Default filter
|
char *filter_exp = ""; // Default filter
|
||||||
char *dev_name = NULL; // Device name
|
char *dev_name = NULL; // Device name
|
||||||
char *dest_ip = NULL; // Destination IP, no default value
|
char *mirror_host = NULL; // Destination IP, no default value
|
||||||
int dest_port = DEFAULT_DEST_PORT; // Destination port, default value
|
int dest_port = DEFAULT_DEST_PORT; // Destination port, default value
|
||||||
int i;
|
int i;
|
||||||
int verbose = 0; // Verbose flag, default is false
|
int verbose = 0; // Verbose flag, default is false
|
||||||
|
int force_ipv4 = 0; // Flag to force IPv4 lookup
|
||||||
|
int force_ipv6 = 0; // Flag to force IPv6 lookup
|
||||||
|
int list_interfaces_flag = 0; // Flag to list interfaces
|
||||||
|
|
||||||
|
// Add a variable to track the count of matching packets
|
||||||
|
int count_packets = 0; // Flag for counting packets
|
||||||
|
unsigned long long int packet_count = 0; // Counter for matching packets (64bit)
|
||||||
|
|
||||||
// Socket variables
|
// Socket variables
|
||||||
int sockfd;
|
int sockfd;
|
||||||
struct sockaddr_in dest_addr;
|
struct addrinfo hints, *res;
|
||||||
|
struct sockaddr_storage dest_addr; // Declare dest_addr
|
||||||
|
int dest_addr_size;
|
||||||
|
|
||||||
// Check if no arguments are given or if help is requested
|
// Check if no arguments are given or if help is requested
|
||||||
if (argc == 1 || (argc == 2 && strcmp(argv[1], "-h") == 0)) {
|
if (argc == 1 || (argc == 2 && strcmp(argv[1], "-h") == 0)) {
|
||||||
@@ -78,18 +157,6 @@ int main(int argc, char *argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create UDP socket
|
|
||||||
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
|
|
||||||
perror("socket");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set destination address
|
|
||||||
memset(&dest_addr, 0, sizeof(dest_addr));
|
|
||||||
dest_addr.sin_family = AF_INET;
|
|
||||||
dest_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // Default to localhost
|
|
||||||
dest_addr.sin_port = htons(dest_port);
|
|
||||||
|
|
||||||
// Parse command-line arguments
|
// Parse command-line arguments
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) {
|
if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) {
|
||||||
@@ -104,56 +171,107 @@ int main(int argc, char *argv[]) {
|
|||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
return 0;
|
return 0;
|
||||||
} else if (strcmp(argv[i], "-r") == 0 && i + 1 < argc) {
|
} else if (strcmp(argv[i], "-r") == 0 && i + 1 < argc) {
|
||||||
dest_ip = argv[i + 1]; // Set destination IP from command line
|
mirror_host = argv[i + 1]; // Set destination IP from command line
|
||||||
i++; // Skip the IP value
|
i++; // Skip the IP value
|
||||||
} else if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
|
} else if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
|
||||||
dest_port = atoi(argv[i + 1]); // Set destination port from command line
|
dest_port = atoi(argv[i + 1]); // Set destination port from command line
|
||||||
i++; // Skip the port value
|
i++; // Skip the port value
|
||||||
|
} else if (strcmp(argv[i], "-4") == 0) {
|
||||||
|
force_ipv4 = 1; // Force IPv4 lookup
|
||||||
|
} else if (strcmp(argv[i], "-6") == 0) {
|
||||||
|
force_ipv6 = 1; // Force IPv6 lookup
|
||||||
|
} else if (strcmp(argv[i], "-l") == 0) {
|
||||||
|
list_interfaces_flag = 1; // Set flag to list interfaces
|
||||||
|
} else if (strcmp(argv[i], "-c") == 0) {
|
||||||
|
count_packets = 1; // Enable packet counting
|
||||||
|
verbose = 0; // Disable verbose mode if -c is set
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (list_interfaces_flag) {
|
||||||
|
list_interfaces();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if destination IP is provided
|
// Check if destination IP is provided
|
||||||
if (dest_ip == NULL) {
|
if (mirror_host == NULL && !list_interfaces_flag) {
|
||||||
fprintf(stderr, "Error: Destination IP address is required.\n");
|
fprintf(stderr, "Error: Destination IP address is required.\n");
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inet_pton(AF_INET, dest_ip, &dest_addr.sin_addr) <= 0) {
|
// Check that interface is not any
|
||||||
perror("inet_pton");
|
if (dev_name != NULL && strcmp(dev_name, "any") == 0) {
|
||||||
|
fprintf(stderr, "Error: Interface 'any' is not supported.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
dest_addr.sin_port = htons(dest_port); // Set the port
|
// Resolve the destination address
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6
|
||||||
|
hints.ai_socktype = SOCK_DGRAM; // Datagram socket
|
||||||
|
|
||||||
// If no interface is specified, find all devices
|
if (force_ipv4) {
|
||||||
if (dev_name == NULL) {
|
hints.ai_family = AF_INET; // Force IPv4
|
||||||
if (pcap_findalldevs(&alldevs, errbuf) == -1) {
|
} else if (force_ipv6) {
|
||||||
fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
|
hints.ai_family = AF_INET6; // Force IPv6
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print the available devices for debugging
|
|
||||||
/*
|
|
||||||
pcap_if_t *device;
|
|
||||||
printf("Available devices:\n");
|
|
||||||
for (device = alldevs; device != NULL; device = device->next) {
|
|
||||||
printf("%s - %s\n", device->name, (device->description != NULL) ? device->description : "No description available");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Use the first device if no device is specified
|
|
||||||
if (alldevs == NULL) {
|
|
||||||
fprintf(stderr, "No devices found. Make sure you have permissions to capture traffic.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_name = alldevs->name; // Use the name of the first device
|
|
||||||
} else {
|
|
||||||
// Interface specified via command line, no need to find all devices
|
|
||||||
alldevs = NULL; // Set alldevs to NULL to avoid potential issues
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getaddrinfo(mirror_host, NULL, &hints, &res) != 0) {
|
||||||
|
perror("getaddrinfo");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate dest_addr size
|
||||||
|
if (res->ai_family == AF_INET) {
|
||||||
|
dest_addr_size = sizeof(struct sockaddr_in);
|
||||||
|
} else if (res->ai_family == AF_INET6) {
|
||||||
|
dest_addr_size = sizeof(struct sockaddr_in6);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Unknown address family\n");
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create UDP socket
|
||||||
|
sockfd = socket(res->ai_family, SOCK_DGRAM, 0);
|
||||||
|
if (sockfd == -1) {
|
||||||
|
perror("socket");
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&dest_addr, 0, sizeof(dest_addr));
|
||||||
|
|
||||||
|
// Set the destination address
|
||||||
|
if (res->ai_family == AF_INET) {
|
||||||
|
struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;
|
||||||
|
ipv4->sin_port = htons(dest_port);
|
||||||
|
memcpy(&dest_addr, ipv4, sizeof(struct sockaddr_in));
|
||||||
|
} else if (res->ai_family == AF_INET6) {
|
||||||
|
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr;
|
||||||
|
ipv6->sin6_port = htons(dest_port);
|
||||||
|
memcpy(&dest_addr, ipv6, sizeof(struct sockaddr_in6));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the destination IP address
|
||||||
|
char resolved_ip[INET6_ADDRSTRLEN];
|
||||||
|
if (res->ai_family == AF_INET) {
|
||||||
|
struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;
|
||||||
|
inet_ntop(AF_INET, &(ipv4->sin_addr), resolved_ip, INET6_ADDRSTRLEN);
|
||||||
|
} else if (res->ai_family == AF_INET6) {
|
||||||
|
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr;
|
||||||
|
inet_ntop(AF_INET6, &(ipv6->sin6_addr), resolved_ip, INET6_ADDRSTRLEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the address info
|
||||||
|
freeaddrinfo(res);
|
||||||
|
|
||||||
|
printf("Using interface: %s\n", dev_name);
|
||||||
|
printf("Using filter: %s\n", filter_exp);
|
||||||
|
printf("Resolved Destination IP: %s\n", resolved_ip);
|
||||||
|
printf("Destination Port: %d\n", dest_port);
|
||||||
|
|
||||||
pcap_t *handle;
|
pcap_t *handle;
|
||||||
struct bpf_program fp;
|
struct bpf_program fp;
|
||||||
bpf_u_int32 mask;
|
bpf_u_int32 mask;
|
||||||
@@ -165,29 +283,20 @@ int main(int argc, char *argv[]) {
|
|||||||
mask = 0;
|
mask = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle = pcap_open_live(dev_name, BUFSIZ, 1, 1000, errbuf);
|
handle = pcap_open_live(dev_name, BUFSIZ, 1, 100, errbuf);
|
||||||
if (handle == NULL) {
|
if (handle == NULL) {
|
||||||
fprintf(stderr, "Couldn't open device %s: %s\n", dev_name, errbuf);
|
fprintf(stderr, "Couldn't open device %s: %s\n", dev_name, errbuf);
|
||||||
if (alldevs != NULL) {
|
|
||||||
pcap_freealldevs(alldevs);
|
|
||||||
}
|
|
||||||
return(2);
|
return(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pcap_compile(handle, &fp, filter_exp, 1, net) == -1) {
|
if (pcap_compile(handle, &fp, filter_exp, 1, net) == -1) {
|
||||||
fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
|
fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
|
||||||
if (alldevs != NULL) {
|
|
||||||
pcap_freealldevs(alldevs);
|
|
||||||
}
|
|
||||||
pcap_close(handle);
|
pcap_close(handle);
|
||||||
return(2);
|
return(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pcap_setfilter(handle, &fp) == -1) {
|
if (pcap_setfilter(handle, &fp) == -1) {
|
||||||
fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
|
fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
|
||||||
if (alldevs != NULL) {
|
|
||||||
pcap_freealldevs(alldevs);
|
|
||||||
}
|
|
||||||
pcap_close(handle);
|
pcap_close(handle);
|
||||||
return(2);
|
return(2);
|
||||||
}
|
}
|
||||||
@@ -195,53 +304,94 @@ int main(int argc, char *argv[]) {
|
|||||||
struct pcap_pkthdr header;
|
struct pcap_pkthdr header;
|
||||||
const u_char *packet;
|
const u_char *packet;
|
||||||
char source_ip_str[INET6_ADDRSTRLEN], dest_ip_str[INET6_ADDRSTRLEN];
|
char source_ip_str[INET6_ADDRSTRLEN], dest_ip_str[INET6_ADDRSTRLEN];
|
||||||
struct ip *ip_header;
|
struct ip *ip_header; // Declare ip4_header
|
||||||
#ifdef ENABLE_IPV6
|
struct ip6_hdr *ip6_header; // Declare ip6_header
|
||||||
struct ip6_hdr *ip6_header;
|
|
||||||
#endif
|
|
||||||
int ip_protocol = 0;
|
int ip_protocol = 0;
|
||||||
|
struct timeval current_time, last_count;
|
||||||
|
|
||||||
printf("Using interface: %s\n", dev_name);
|
gettimeofday(&last_count, NULL);
|
||||||
printf("Using filter: %s\n", filter_exp);
|
printf("\n");
|
||||||
printf("Destination IP: %s\n", dest_ip);
|
|
||||||
printf("Destination Port: %d\n", dest_port);
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
packet = pcap_next(handle, &header);
|
packet = pcap_next(handle, &header);
|
||||||
if (packet == NULL)
|
if (packet == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Assuming Ethernet header is 14 bytes
|
if (count_packets) {
|
||||||
// Check IP version
|
packet_count++;
|
||||||
ip_header = (struct ip*)(packet + ETHERNET_HEADER_LENGTH);
|
|
||||||
ip_protocol = ip_header->ip_v;
|
|
||||||
|
|
||||||
if (ip_protocol == 4) {
|
gettimeofday(¤t_time, NULL);
|
||||||
// IPv4
|
|
||||||
inet_ntop(AF_INET, &(ip_header->ip_src), source_ip_str, INET6_ADDRSTRLEN);
|
|
||||||
inet_ntop(AF_INET, &(ip_header->ip_dst), dest_ip_str, INET6_ADDRSTRLEN);
|
|
||||||
|
|
||||||
if (verbose) {
|
long elapsed_ms = current_time.tv_sec * 1000 + (current_time.tv_usec /1000)-
|
||||||
printf("IPv4 Packet: %s -> %s, IP Protocol: %d\n",
|
(last_count.tv_sec * 1000 + (last_count.tv_usec /1000));
|
||||||
source_ip_str, dest_ip_str, ip_header->ip_p);
|
|
||||||
|
if (elapsed_ms >= 500) {
|
||||||
|
printf("\rPacket count: %llu", packet_count);
|
||||||
|
fflush(stdout);
|
||||||
|
last_count = current_time; // Reset the timer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_IPV6
|
|
||||||
else if (ip_protocol == 6) {
|
|
||||||
// IPv6
|
|
||||||
ip6_header = (struct ip6_hdr*)(packet + ETHERNET_HEADER_LENGTH);
|
|
||||||
inet_ntop(AF_INET6, &(ip6_header->ip6_src), source_ip_str, INET6_ADDRSTRLEN);
|
|
||||||
inet_ntop(AF_INET6, &(ip6_header->ip6_dst), dest_ip_str, INET6_ADDRSTRLEN);
|
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("IPv6 Packet: %s -> %s, Next Header: %d\n",
|
|
||||||
source_ip_str, dest_ip_str, ip6_header->ip6_nxt);
|
// Parse Ethernet header
|
||||||
|
struct ether_header *eth_header = (struct ether_header *)packet;
|
||||||
|
|
||||||
|
// Check EtherType
|
||||||
|
uint16_t ether_type = ntohs(eth_header->ether_type);
|
||||||
|
|
||||||
|
int vlan_offset = 0; // Offset for VLAN-tagged packets
|
||||||
|
|
||||||
|
// Check for VLAN tags (including Q-in-Q)
|
||||||
|
while (ether_type == 0x8100 || ether_type == 0x88A8) {
|
||||||
|
// VLAN tag is present
|
||||||
|
vlan_offset += 4; // Each VLAN tag adds 4 bytes
|
||||||
|
uint16_t vlan_tag = ntohs(*(uint16_t *)(packet + ETHERNET_HEADER_LENGTH + vlan_offset - 4));
|
||||||
|
uint16_t vlan_id = vlan_tag & 0x0FFF; // Extract VLAN ID (12 bits)
|
||||||
|
uint8_t vlan_pcp = (vlan_tag >> 13) & 0x07; // Extract Priority Code Point (3 bits)
|
||||||
|
uint8_t vlan_dei = (vlan_tag >> 12) & 0x01; // Extract Drop Eligible Indicator (1 bit)
|
||||||
|
|
||||||
|
printf("VLAN Tag: VLAN ID=%d, PCP=%d, DEI=%d\n", vlan_id, vlan_pcp, vlan_dei);
|
||||||
|
|
||||||
|
// Update EtherType to the next protocol
|
||||||
|
ether_type = ntohs(*(uint16_t *)(packet + ETHERNET_HEADER_LENGTH + vlan_offset - 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ether_type == ETHERTYPE_IP) {
|
||||||
|
// Handle IPv4 traffic
|
||||||
|
ip_header = (struct ip *)(packet + ETHERNET_HEADER_LENGTH + vlan_offset);
|
||||||
|
ip_protocol = ip_header->ip_v & 0x0F; // Get IP version
|
||||||
|
|
||||||
|
if (ip_protocol == 4) {
|
||||||
|
inet_ntop(AF_INET, &(ip_header->ip_src.s_addr), source_ip_str, INET6_ADDRSTRLEN);
|
||||||
|
inet_ntop(AF_INET, &(ip_header->ip_dst.s_addr), dest_ip_str, INET6_ADDRSTRLEN);
|
||||||
|
|
||||||
|
printf("IPv4 Packet: %s -> %s, IP Protocol: %s\n",
|
||||||
|
source_ip_str, dest_ip_str, lookup_protocol_name(ip_header->ip_p));
|
||||||
|
}
|
||||||
|
} else if (ether_type == ETHERTYPE_IPV6) {
|
||||||
|
// Handle IPv6 traffic
|
||||||
|
ip6_header = (struct ip6_hdr *)(packet + ETHERNET_HEADER_LENGTH + vlan_offset);
|
||||||
|
inet_ntop(AF_INET6, &(ip6_header->ip6_src), source_ip_str, INET6_ADDRSTRLEN);
|
||||||
|
inet_ntop(AF_INET6, &(ip6_header->ip6_dst), dest_ip_str, INET6_ADDRSTRLEN);
|
||||||
|
|
||||||
|
printf("IPv6 Packet: %s -> %s, Next Header: %s\n",
|
||||||
|
source_ip_str, dest_ip_str, lookup_protocol_name(ip6_header->ip6_nxt));
|
||||||
|
} else if (ether_type == ETHERTYPE_ARP) {
|
||||||
|
// Handle ARP traffic
|
||||||
|
struct arp_header *arp = (struct arp_header *)(packet + ETHERNET_HEADER_LENGTH + vlan_offset);
|
||||||
|
|
||||||
|
printf("ARP Packet: Operation: %s\n",
|
||||||
|
(ntohs(arp->oper) == 1) ? "Request" : "Reply");
|
||||||
|
printf("Sender MAC: %02x:%02x:%02x:%02x:%02x:%02x, Sender IP: %d.%d.%d.%d\n",
|
||||||
|
arp->sha[0], arp->sha[1], arp->sha[2], arp->sha[3], arp->sha[4], arp->sha[5],
|
||||||
|
arp->spa[0], arp->spa[1], arp->spa[2], arp->spa[3]);
|
||||||
|
printf("Target MAC: %02x:%02x:%02x:%02x:%02x:%02x, Target IP: %d.%d.%d.%d\n",
|
||||||
|
arp->tha[0], arp->tha[1], arp->tha[2], arp->tha[3], arp->tha[4], arp->tha[5],
|
||||||
|
arp->tpa[0], arp->tpa[1], arp->tpa[2], arp->tpa[3]);
|
||||||
|
} else {
|
||||||
|
printf("Non-IP/ARP Packet, EtherType: 0x%04x\n", ether_type);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else {
|
|
||||||
printf("Non-IP Packet\n");
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create TZSP Header
|
// Create TZSP Header
|
||||||
@@ -274,7 +424,7 @@ int main(int argc, char *argv[]) {
|
|||||||
memcpy(ptr, packet, header.caplen);
|
memcpy(ptr, packet, header.caplen);
|
||||||
|
|
||||||
// Send packet via UDP with TZSP encapsulation
|
// Send packet via UDP with TZSP encapsulation
|
||||||
if (sendto(sockfd, tzsp_packet, total_length, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) == -1) {
|
if (sendto(sockfd, tzsp_packet, total_length, 0, (struct sockaddr *)&dest_addr, dest_addr_size) == -1) {
|
||||||
perror("sendto");
|
perror("sendto");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,9 +433,6 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
pcap_freecode(&fp);
|
pcap_freecode(&fp);
|
||||||
pcap_close(handle);
|
pcap_close(handle);
|
||||||
if (alldevs != NULL) {
|
|
||||||
pcap_freealldevs(alldevs); // Free the device list only if devices were found
|
|
||||||
}
|
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
64
pcapmirror.8
Normal file
64
pcapmirror.8
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
.TH PCAPMIRROR 1 "March 24, 2025" "pcapmirror 0.5" "User Commands"
|
||||||
|
.SH NAME
|
||||||
|
pcapmirror \- A command-line tool for capturing and mirroring network traffic
|
||||||
|
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B pcapmirror
|
||||||
|
[\fIoptions\fR]
|
||||||
|
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B pcapmirror
|
||||||
|
is a command-line tool for capturing network traffic and mirroring it to a remote destination using TZSP encapsulation. It leverages the \fBlibpcap\fR library for packet capture and provides options for filtering traffic based on BPF syntax. This tool is useful for network monitoring, intrusion detection, and remote packet analysis.
|
||||||
|
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.B \-i \fIinterface\fR
|
||||||
|
Specify the capture interface (e.g., eth0).
|
||||||
|
.TP
|
||||||
|
.B \-f \fIfilter\fR
|
||||||
|
Specify the capture filter in BPF syntax (e.g., tcp port 80).
|
||||||
|
.TP
|
||||||
|
.B \-r \fIhost/ipv4/ipv6\fR
|
||||||
|
Specify the destination host (required).
|
||||||
|
.TP
|
||||||
|
.B \-p \fIport\fR
|
||||||
|
Specify the destination port (default: 37008).
|
||||||
|
.TP
|
||||||
|
.B \-4
|
||||||
|
Force IPv4 host lookup.
|
||||||
|
.TP
|
||||||
|
.B \-6
|
||||||
|
Force IPv6 host lookup.
|
||||||
|
.TP
|
||||||
|
.B \-l
|
||||||
|
List available network interfaces.
|
||||||
|
.TP
|
||||||
|
.B \-v
|
||||||
|
Enable verbose mode (prints packet information).
|
||||||
|
.TP
|
||||||
|
.B \-c
|
||||||
|
Count matching packets (overrides verbose mode)
|
||||||
|
.TP
|
||||||
|
.B \-h
|
||||||
|
Show this help message.
|
||||||
|
|
||||||
|
.SH EXAMPLES
|
||||||
|
To capture traffic on the eth0 interface, filter for TCP port 80, and send it to the destination, use the following command:
|
||||||
|
|
||||||
|
.EX
|
||||||
|
sudo pcapmirror -i eth0 -f "tcp port 80" -r 192.168.1.100 -p 47008 -v
|
||||||
|
.EE
|
||||||
|
|
||||||
|
.SH USAGE WITH WIRESHARK
|
||||||
|
With this tool, you can mirror traffic directly to a running Wireshark.
|
||||||
|
|
||||||
|
To avoid capturing traffic from your own monitoring machine, configure Wireshark with a capture filter of udp port 37008 or udp dst port 37008. Also, verify that your firewall permits this UDP traffic.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR bpf (2), tcpdump (1), wireshark (1), pcap (3)
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
Matthias Cramer <cramer@freestone.net>
|
||||||
|
|
||||||
|
.SH COPYRIGHT
|
||||||
|
Copyright (c) 2025, Matthias Cramer. All rights reserved.
|
||||||
41
pcapmirror.spec
Normal file
41
pcapmirror.spec
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
Name: pcapmirror
|
||||||
|
Version: 0.5
|
||||||
|
Release: %(perl -e 'print time()')%{?dist}
|
||||||
|
Summary: A simple packet capture mirror
|
||||||
|
License: BSD 3-Clause License
|
||||||
|
URL: https://git.freestone.net/cramer/pcapmirror
|
||||||
|
Source: https://git.freestone.net/cramer/pcapmirror/-/archive/v%version/pcapmirror-v%version.tar.gz
|
||||||
|
BuildRequires: gcc
|
||||||
|
BuildRequires: make
|
||||||
|
BuildRequires: libpcap-devel
|
||||||
|
|
||||||
|
%description
|
||||||
|
pcapmirror is a command-line tool for capturing and mirroring network traffic using TZSP encapsulation. It leverages the `libpcap` library for packet capture and supports BPF syntax for filtering traffic.
|
||||||
|
|
||||||
|
%build
|
||||||
|
%make_build
|
||||||
|
|
||||||
|
%install
|
||||||
|
%make_install
|
||||||
|
|
||||||
|
%files
|
||||||
|
%{_bindir}/pcapmirror
|
||||||
|
%{_mandir}/man8/pcapmirror.8.gz
|
||||||
|
%license LICENSE
|
||||||
|
%doc README.md
|
||||||
|
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Sat Mar 29 2025 Matthias Cramer <cramer@freesone.net> 0.5-1
|
||||||
|
- new option -c to count matching packets (overrides verbose mode)
|
||||||
|
- reworked packet decoder to also decode arp, vlan and qinq packets
|
||||||
|
- well known protocols numbers are now decoded
|
||||||
|
- works now on MacOS and OpenBSD
|
||||||
|
* Mon Mar 24 2025 Matthias Cramer <cramer@freesone.net> 0.4-1
|
||||||
|
- IPv6 support for remote destination
|
||||||
|
- remote destination can now also be hostname
|
||||||
|
- added option to enforce IPv4 and IPv6 for remote destination
|
||||||
|
* Sat Mar 22 2025 Matthias Cramer <cramer@freesone.net> 0.3-1
|
||||||
|
- added manpage
|
||||||
|
* Sat Mar 22 2025 Matthias Cramer <cramer@freesone.net> 0.2-1
|
||||||
|
- Initial release of pcapmirror
|
||||||
Reference in New Issue
Block a user