Compare commits

...

35 Commits
v0.2 ... 0.3-7

Author SHA1 Message Date
4300e30f04 propper ip6 support, raspberry builds 2025-03-23 13:55:17 +01:00
0fdd4a9783 updated readme and added logos 2025-03-23 11:20:39 +01:00
49173fef25 let's try again 2025-03-22 19:00:45 +01:00
8e586dade0 paralell 2025-03-22 18:28:55 +01:00
c7e16616a1 again for the stupid ones 2025-03-22 18:11:13 +01:00
9d91fda7e1 PACKAGENAME not defined 2025-03-22 18:08:15 +01:00
3c007c3fcc test2 2025-03-22 18:04:29 +01:00
8ff71daa36 upload debug 2025-03-22 18:01:26 +01:00
3a078c5ba2 try to upload artifacts to registry 2025-03-22 17:39:09 +01:00
232fe98fd9 rocky needs the v 2025-03-22 16:42:42 +01:00
9e30e4e7aa version bump to 0.3 2025-03-22 16:40:49 +01:00
2f4c086eba typo 2025-03-22 16:33:59 +01:00
e76fb7e61f does not need to be in the repository 2025-03-22 16:31:20 +01:00
269488b60d man install fix 2025-03-22 16:31:16 +01:00
b07369b5b0 rename target 2025-03-22 16:09:15 +01:00
8e01a2823c rl8 only tags 2025-03-22 16:06:19 +01:00
d86c3829f5 manpage info packages 2025-03-22 16:05:37 +01:00
1471e39e50 man page 2025-03-22 14:23:29 +01:00
0ffa2b82bf changelog2 2025-03-22 14:09:17 +01:00
f3604f7390 changelog 2025-03-22 14:07:09 +01:00
0a71915fd8 rocky8 2025-03-22 14:03:31 +01:00
f207c5bdc2 ts 2025-03-22 13:56:41 +01:00
8869da41b5 release dist? 2025-03-22 13:54:33 +01:00
f1c0985c99 less is more 2025-03-22 13:49:51 +01:00
bc23a64b46 -v 2025-03-22 13:48:46 +01:00
b334754945 source 2025-03-22 13:47:10 +01:00
faece01978 tar.gz 2025-03-22 13:45:47 +01:00
02c69f2936 -r 2025-03-22 13:43:48 +01:00
c2475e04f9 mkdir 2025-03-22 13:42:43 +01:00
ba55d4d958 BUILD 2025-03-22 13:40:53 +01:00
b176c8edef dnf 2025-03-22 13:03:18 +01:00
1d67a904b9 sequence error 2025-03-22 13:02:22 +01:00
646a888e84 libpcap-devel 2025-03-22 13:00:59 +01:00
aa86180054 : 2025-03-22 12:59:31 +01:00
94266b53a9 rpm build 2025-03-22 12:58:26 +01:00
12 changed files with 346 additions and 74 deletions

2
.gitignore vendored
View File

@@ -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

View File

@@ -1,18 +1,21 @@
stages: stages:
- build - build
- publish
variables: variables:
DEBIAN_FRONTEND: noninteractive DEBIAN_FRONTEND: noninteractive
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_0.3.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,33 @@ 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
- 'echo "Uploading to: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/bookworm/pcapmirror_0.3-1_amd64.deb"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/pcapmirror_0.3-1_amd64.deb ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/bookworm/pcapmirror_0.3-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_0.3.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 +57,131 @@ 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
- 'echo "Uploading to: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/sid/pcapmirror_0.3-1_amd64.deb"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/pcapmirror_0.3-1_amd64.deb ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/sid/pcapmirror_0.3-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-v0.3.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
- 'echo "Uploading to: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/rockylinux9/pcapmirror-0.3-1.el8.x86_64.rpm"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/pcapmirror-0.3-*.el9.x86_64.rpm ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/rockylinux9/pcapmirror-0.3-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-v0.3.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
- 'echo "Uploading to: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/rockylinux8/pcapmirror-0.3-1.el8.x86_64.rpm"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/pcapmirror-0.3-*.el8.x86_64.rpm ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/rockylinux8/pcapmirror-0.3-1.el8.x86_64.rpm'
build-pios12:
stage: build
needs: []
only:
- tags
tags:
- pios12
script:
- dnf install -y libpcap-devel
- mkdir -p /root/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
- tar -czf /root/rpmbuild/SOURCES/pcapmirror-v0.3.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-pios12:
stage: publish
needs:
- build-rpios12
dependencies:
- build-pios12
only:
- tags
tags:
- bookworm
script:
- apt-get update && apt-get install -y curl
- ls -la build
- 'echo "Uploading to: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/bookworm/pcapmirror_0.3-1_arm64.deb"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/pcapmirror_0.3-1_arm64.deb ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pcapmirror/bookworm/pcapmirror_0.3-1_arm64.deb'

View File

@@ -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)

View File

@@ -1,4 +1,7 @@
# pcapmirror # pcapmirror
![pcapmirror logo](logo/pcapmirror_logo_small.png)
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,14 @@ 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
* -v Enable verbose mode
* -h Show this help message
### Example: ### Example:
@@ -45,7 +50,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 +62,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
``` ```

6
debian/changelog vendored
View File

@@ -1,3 +1,9 @@
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
View File

@@ -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

1
debian/install vendored
View File

@@ -1 +1,2 @@
pcapmirror /usr/bin pcapmirror /usr/bin
pcapmirror.8 /usr/share/man/man8

BIN
logo/pcapmirror_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

120
main.c
View File

@@ -13,13 +13,9 @@ Copyright (c) 2025, Matthias Cramer, cramer@freestone.net
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h>
#include <unistd.h> #include <unistd.h>
#include <netinet/ip6.h>
#define ENABLE_IPV6
#ifdef ENABLE_IPV6
#include <netinet/ip6.h> // Include for IPv6 header definition
#endif
#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
@@ -48,12 +44,14 @@ int is_little_endian() {
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(" -v Enable 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);
} }
@@ -63,14 +61,17 @@ int main(int argc, char *argv[]) {
char errbuf[PCAP_ERRBUF_SIZE]; char errbuf[PCAP_ERRBUF_SIZE];
char *filter_exp = "tcp port 8088"; // Default filter char *filter_exp = "tcp port 8088"; // 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
// 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
// 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 +79,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,27 +93,77 @@ 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
} }
} }
// Check if destination IP is provided // Check if destination IP is provided
if (dest_ip == NULL) { if (mirror_host == NULL) {
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) { // Resolve the destination address
perror("inet_pton"); memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6
hints.ai_socktype = SOCK_DGRAM; // Datagram socket
if (force_ipv4) {
hints.ai_family = AF_INET; // Force IPv4
} else if (force_ipv6) {
hints.ai_family = AF_INET6; // Force IPv6
}
if (getaddrinfo(mirror_host, NULL, &hints, &res) != 0) {
perror("getaddrinfo");
return 1; return 1;
} }
dest_addr.sin_port = htons(dest_port); // Set the port // Create UDP socket
sockfd = socket(res->ai_family, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket");
freeaddrinfo(res);
return 1;
}
// 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);
// If no interface is specified, find all devices // If no interface is specified, find all devices
if (dev_name == NULL) { if (dev_name == NULL) {
@@ -195,17 +234,10 @@ 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;
printf("Using interface: %s\n", dev_name);
printf("Using filter: %s\n", filter_exp);
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)
@@ -225,9 +257,7 @@ int main(int argc, char *argv[]) {
printf("IPv4 Packet: %s -> %s, IP Protocol: %d\n", printf("IPv4 Packet: %s -> %s, IP Protocol: %d\n",
source_ip_str, dest_ip_str, ip_header->ip_p); source_ip_str, dest_ip_str, ip_header->ip_p);
} }
} } else if (ip_protocol == 6) {
#ifdef ENABLE_IPV6
else if (ip_protocol == 6) {
// IPv6 // IPv6
ip6_header = (struct ip6_hdr*)(packet + ETHERNET_HEADER_LENGTH); 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_src), source_ip_str, INET6_ADDRSTRLEN);
@@ -237,9 +267,7 @@ int main(int argc, char *argv[]) {
printf("IPv6 Packet: %s -> %s, Next Header: %d\n", printf("IPv6 Packet: %s -> %s, Next Header: %d\n",
source_ip_str, dest_ip_str, ip6_header->ip6_nxt); source_ip_str, dest_ip_str, ip6_header->ip6_nxt);
} }
} } else {
#endif
else {
printf("Non-IP Packet\n"); printf("Non-IP Packet\n");
continue; continue;
} }

58
pcapmirror.8 Normal file
View File

@@ -0,0 +1,58 @@
.TH PCAPMIRROR 1 "March 22, 2025" "pcapmirror 0.3" "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 \-v
Enable verbose mode (prints packet information).
.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.

32
pcapmirror.spec Normal file
View File

@@ -0,0 +1,32 @@
Name: pcapmirror
Version: 0.3
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 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