Skip to content

Commit

Permalink
Capture all packets by default, even if process info cannot be associ…
Browse files Browse the repository at this point in the history
…ated

The before default is to only capture packets that can be associated with process information.

Closes #17
  • Loading branch information
mozillazg committed May 7, 2024
1 parent 0c197ae commit 2630ac9
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 26 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ jobs:
cmd: |
chmod +x /host/ptcpdump/ptcpdump
- name: Test default
uses: cilium/little-vm-helper@908ab1ff8a596a03cd5221a1f8602dc44c3f906d # v0.0.12
with:
provision: 'false'
dns-resolver: '1.1.1.1'
cmd: |
set -ex
uname -a
cat /etc/issue
bash /host/testdata/test_default.sh /host/ptcpdump/ptcpdump
- name: Test base
uses: cilium/little-vm-helper@908ab1ff8a596a03cd5221a1f8602dc44c3f906d # v0.0.12
with:
Expand Down
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ deps:

.PHONY: e2e
e2e: generate build
sudo rm -rf /tmp/ptcpdump_*
sudo bash testdata/test_default.sh ./ptcpdump
sudo bash testdata/test_base.sh ./ptcpdump
sudo bash testdata/test_pname_filter.sh ./ptcpdump
sudo bash testdata/test_pid_filter.sh ./ptcpdump
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Usage:
ptcpdump [flags] [expression]
Examples:
ptcpdump -i any
ptcpdump -i any tcp
ptcpdump -i eth0 --pid 1234 port 80 and host 10.10.1.1
Expand All @@ -62,8 +62,8 @@ Flags:
-h, --help help for ptcpdump
-i, --interface strings Interfaces to capture (default [lo])
--list-interfaces Print the list of the network interfaces available on the system
--pid uint Filter by process ID
--pname string Filter by process name
--pid uint Filter by process ID (only TCP and UDP packets are supported)
--pname string Filter by process name (only TCP and UDP packets are supported)
--print Print parsed packet output, even if the raw packets are being saved to a file with the -w flag
-r, --read-file string Read packets from file (which was created with the -w option). e.g. ptcpdump.pcapng
-c, --receive-count uint Exit after receiving count packets
Expand Down
Binary file modified bpf/bpf_x86_bpfel.o
Binary file not shown.
35 changes: 22 additions & 13 deletions bpf/ptcpdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,13 @@ static __always_inline bool str_cmp(const char *a, const volatile char *b, int l
return 0;
}

static __always_inline bool have_pid_filter_rules() {
return filter_pid > 0 || filter_comm_enable == 1;
}

static __always_inline int process_filter(struct task_struct *task) {
// no filter rules
if (filter_pid < 1 && filter_comm_enable != 1) {
if (!have_pid_filter_rules()) {
return 0;
}

Expand Down Expand Up @@ -408,7 +412,8 @@ static __always_inline void handle_tc(struct __sk_buff *skb, bool egress) {
return;
}


bool have_pid_filter = have_pid_filter_rules();
struct flow_pid_value_t *pid_meta;
struct flow_pid_key_t key = {0};
if (egress) {
key.saddr[0] = packet_meta.l3.saddr[0];
Expand All @@ -424,19 +429,21 @@ static __always_inline void handle_tc(struct __sk_buff *skb, bool egress) {
key.sport = packet_meta.l4.dport;
}

if (key.sport == 0) {
if (have_pid_filter && key.sport == 0) {
return;
}


/* bpf_printk("[tc] %pI4 %d", &key.saddr[0], key.sport); */
if (key.sport > 0) {
/* bpf_printk("[tc] %pI4 %d", &key.saddr[0], key.sport); */

struct flow_pid_value_t *value = bpf_map_lookup_elem(&flow_pid_map, &key);
if (value) {
// bpf_printk("[tc] (%s) %pI4 %d", value->comm, &key.saddr[0], key.sport);
} else {
/* bpf_printk("[tc] %pI4 %d bpf_map_lookup_elem is empty", &key.saddr[0], key.sport); */
return;
pid_meta = bpf_map_lookup_elem(&flow_pid_map, &key);
if (pid_meta) {
// bpf_printk("[tc] (%s) %pI4 %d", pid_meta->comm, &key.saddr[0], key.sport);
} else if (have_pid_filter) {
/* bpf_printk("[tc] %pI4 %d bpf_map_lookup_elem is empty", &key.saddr[0], key.sport); */
return;
}
}

struct packet_event_t *event;
Expand All @@ -445,7 +452,7 @@ static __always_inline void handle_tc(struct __sk_buff *skb, bool egress) {
bpf_printk("[ptcpdump] packet_event_stack failed");
return;
}
// __builtin_memset(event, 0, sizeof(*event));
/* __builtin_memset(event->payload, 0, sizeof(event->payload)); */

if (egress) {
event->meta.packet_type = EGRESS_PACKET;
Expand All @@ -454,8 +461,10 @@ static __always_inline void handle_tc(struct __sk_buff *skb, bool egress) {
}
event->meta.timestamp = bpf_ktime_get_ns();
event->meta.ifindex = packet_meta.ifindex;
event->meta.pid = value->pid;
/* __builtin_memcpy(&event->meta.comm, &value->comm, sizeof(value->comm)); */
if (pid_meta) {
event->meta.pid = pid_meta->pid;
/* __builtin_memcpy(&event->meta.comm, &pid_meta->comm, sizeof(pid_meta->comm)); */
}

u64 payload_len = (u64)skb->len;
event->meta.packet_size = payload_len;
Expand Down
6 changes: 3 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var rootCmd = &cobra.Command{
Use: `ptcpdump [flags] [expression]
Examples:
ptcpdump -i any
ptcpdump -i any tcp
ptcpdump -i eth0 --pid 1234 port 80 and host 10.10.1.1
Expand Down Expand Up @@ -43,8 +43,8 @@ func init() {
"Read packets from file (which was created with the -w option). e.g. ptcpdump.pcapng")
rootCmd.Flags().StringSliceVarP(&opts.ifaces, "interface", "i", []string{"lo"},
"Interfaces to capture")
rootCmd.Flags().UintVar(&opts.pid, "pid", 0, "Filter by process ID")
rootCmd.Flags().StringVar(&opts.comm, "pname", "", "Filter by process name")
rootCmd.Flags().UintVar(&opts.pid, "pid", 0, "Filter by process ID (only TCP and UDP packets are supported)")
rootCmd.Flags().StringVar(&opts.comm, "pname", "", "Filter by process name (only TCP and UDP packets are supported)")
rootCmd.Flags().BoolVarP(&opts.followForks, "follow-forks", "f", false,
"Trace child processes as they are created by currently traced processes when filter by process")
rootCmd.Flags().BoolVar(&opts.listInterfaces, "list-interfaces", false,
Expand Down
14 changes: 7 additions & 7 deletions internal/writer/pcapng.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ package writer

import (
"fmt"

"github.com/gopacket/gopacket"
"github.com/gopacket/gopacket/pcapgo"
"github.com/mozillazg/ptcpdump/internal/event"
"github.com/mozillazg/ptcpdump/internal/metadata"
"golang.org/x/xerrors"
"log"
)

type PcapNGWriter struct {
Expand All @@ -28,12 +28,12 @@ func (w *PcapNGWriter) Write(e *event.Packet) error {
InterfaceIndex: e.Device.Ifindex,
}
p := w.pcache.Get(e.Pid)
if p.Pid == 0 {
log.Printf("not found pid from cache: %d", e.Pid)
}
opts := pcapgo.NgPacketOptions{
Comment: fmt.Sprintf("PID: %d\nCommand: %s\nArgs: %s",
e.Pid, p.FilenameStr(), p.ArgsStr()),

opts := pcapgo.NgPacketOptions{}
if p.Pid != 0 {
// log.Printf("not found pid from cache: %d", e.Pid)
opts.Comment = fmt.Sprintf("PID: %d\nCommand: %s\nArgs: %s",
e.Pid, p.FilenameStr(), p.ArgsStr())
}

if err := w.pw.WritePacketWithOptions(info, e.Data, opts); err != nil {
Expand Down
43 changes: 43 additions & 0 deletions testdata/test_default.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash

set -ex

CMD="$1"
FILE_PREFIX="/tmp/ptcpdump"
FNAME="${FILE_PREFIX}_default.pcapng"
LNAME="${FILE_PREFIX}_default.log"
RNAME="${FILE_PREFIX}_default.read.txt"


function test_ptcpdump() {
timeout 30s ${CMD} -c 2 -i lo --print -w "${FNAME}" \
'icmp and host 127.0.0.1' | tee "${LNAME}" &
sleep 10
ping -c 1 127.0.0.1 &>/dev/null || true
wait

cat "${LNAME}"
cat "${LNAME}" | grep -F '127.0.0.1 > 127.0.0.1: ICMP echo request'
}

function test_tcpdump_read() {
which tcpdump || (apt update || true && apt install -y tcpdump)
tcpdump -nr "${FNAME}"
tcpdump -nr "${FNAME}" | grep -F '127.0.0.1 > 127.0.0.1: ICMP echo request'

}

function test_ptcpdump_read() {
EXPECT_NAME="${LNAME}.read.expect"
sed 's/ [a-zA-Z0-9_-]\+ \(In\|Out\) / /g' "${LNAME}" > "${EXPECT_NAME}"
timeout 30s ${CMD} -r "${FNAME}" > "${RNAME}"
diff "${EXPECT_NAME}" "${RNAME}"
}

function main() {
test_ptcpdump
test_tcpdump_read
test_ptcpdump_read
}

main

0 comments on commit 2630ac9

Please sign in to comment.