Wireshark-dev: [Wireshark-dev] Proposal: capture-time process attribution in dumpcap and pcapng

From: Fidel Perez-Smith <fiddyschmitt@xxxxxxxxx>
Date: Fri, 11 Sep 2026 22:35:54 +1000
To: wireshark-dev@xxxxxxxxxxxxx
Subject: Proposal: capture-time process attribution in dumpcap and pcapng

Hi all,

Following Alexis's suggestion on issue #17525 [1], I'd like to add
process attribution to Wireshark proper: which local process sent or
received each packet (PID, name, path, command line, user), recorded
by dumpcap at capture time and stored in the pcapng file, on Windows,
Linux and macOS. It is the C rewrite of the Lua plugin I posted there
[2], which does the lookup at display time and therefore cannot travel
with the capture.

Before opening merge requests I'd appreciate a sanity check of the
design. It deliberately builds on what landed in 4.6 for Darwin
(!19734) and takes the review feedback on !17737 into account.

File format
-----------
- Per packet: the existing standard option epb_processid_threadid
  (code 8), which wiretap already reads and writes. Nothing in
  Wireshark produces or displays it today.
- Per process: a new Process Information Block, one per distinct
  process, with options for name, path, command line, parent PID,
  uid, user name, executable UUID and start time, referenced from
  packets by a repeatable epb_pib_index option. This is Apple's DPIB
  generalised, and close to Hone's process block. I have drafted the
  text for the pcapng draft as a PR [4] that picks up spec issue #164 [3],
  proposing block type 0x0000000B and EPB option 9.
- Until the spec assigns codes, dumpcap writes the same content as a
  Wireshark Custom Block / Custom Option under the Foundation's PEN
  32622, following the PcapngCustom wiki scheme. wiretap reads both
  through one path, so files written in the interim keep working.

Wireshark side
--------------
- wiretap: turn the DPIB side table into a generic process table
  (read, write-back, merge). Darwin's 0x80000001 block keeps being
  read and populates the same table.
- epan: extend epan_get_process_id/name/uuid() with path, command
  line, user, parent and start time. A new packet-process.c registers
  frame.process.pid/tid/name/path/cmdline/ppid/uid/user/uuid/
  start_time under the frame protocol (like frame.bblog and
  frame.darwin), sets pinfo->user_name and registers a "Process"
  conversation filter. Columns are then plain custom columns; no new
  column type.
- wsutil: a portable socket-to-process lookup with one backend per
  OS and no new dependencies:
    Windows: GetExtendedTcpTable/GetExtendedUdpTable (all users, no
             elevation); names via QueryFullProcessImageName.
    macOS:   sysctl net.inet.{tcp,udp}.pcblist_n, whose socket
             records carry so_last_pid/so_e_pid (what netstat -v
             prints; all users, no root).
    Linux:   NETLINK_SOCK_DIAG for the socket list, /proc for the
             inode-to-PID step and the details. Own-user processes
             need nothing extra; other users need CAP_SYS_PTRACE,
             which dumpcap would keep only while the option is on
             and only if the administrator granted it. No
             CAP_SYS_ADMIN, no libbpf.
  Other platforms get a stub; FreeBSD would be a natural follow-up.
- dumpcap: --process-info (also a capture preference in the GUI),
  off by default, pcapng only. The 5-tuple is parsed for Ethernet,
  SLL/SLL2, NULL/LOOP, raw IP and 802.1Q; only TCP and UDP are looked
  up; results are cached; a miss never delays or aborts the capture.
  PIBs are replayed on ring-buffer file switches like IDBs are.

Known limit: a socket table is polled, so a socket that opens and
closes between two snapshots is missed. Kernel-stamped "exact" modes
(PKTAP on macOS, ETW on Windows, eBPF on Linux) are possible later as
separate, optional proposals and are out of scope for this series.

Merge requests, each one squashed commit:
  1. frame: dissect epb_processid_threadid into frame.process.pid/tid
  2. wiretap: generic process information table (+ file-pcapng, tests)
  3. epan: frame.process.* fields and Process conversation filter
  4. wsutil: portable socket-to-process lookup (+ unit tests)
  5. dumpcap: --process-info (+ writecap, man pages, capture test)
  6. Qt: capture preference and checkbox

Questions:
  a) Is reusing option 8 for the per-packet PID acceptable alongside
     an index into the process block, or would you rather see only
     the index?
  b) Any objection to the interim Custom Block under PEN 32622?
  c) Anything in the Darwin/DPIB code you would like reshaped while
     it is being generalised?

I'll disclose AI assistance (Assisted-by: Claude) in the commits.

Thanks,
Fidel + Fable 5.1

[1] https://gitlab.com/wireshark/wireshark/-/issues/17525
[2] https://github.com/fiddyschmitt/wireshark-process-dissector
[3] https://github.com/IETF-OPSAWG-WG/draft-ietf-opsawg-pcap/issues/164
[4] https://github.com/IETF-OPSAWG-WG/draft-ietf-opsawg-pcap/pull/209