This is still an issue with OS X Mojave 10.14.2 (libpcap 1.0.1 Apple 79.200.4, tcpdump 4.9.2 Apple 83.200.2). It's ultimately a bug in Apple's patches to libpcap and tcpdump.
In addition to using upstream tcpdump (which is available in Homebrew), you could also:
Use tshark (part of Wireshark), which works similarly to tcpdump.
Write the packets to a temporary file.
Prefix the stream with 4 null bytes:
sudo tcpdump -i en0 -w - | cat <(printf "\0\0\0\0") - | tcpdump -nvr -
Cause (and why inserting nulls works)
Apple has patched their tcpdump such that it tries to read files as PCAP-NG format first:
#else /* __APPLE__ */
pd = pcap_ng_open_offline(RFileName, ebuf);
They also added a -P option to emit packets in pcapng format.
pcap_ng_open_offline ends up in pcap_fopen_offline_internal(..., isng=1). This flow calls pcap_ng_check_header early (see if (isng) in pcap_fopen_offline_internal), and on failure, jumps into the bad: label.
That bad: label attempts to fseeko to seek the file back to the start:
bad:
fseeko(fp, offset, SEEK_SET);
if (p != NULL)
free(p);
return (NULL);
But you can't seek a FIFO, so we're still reading from the same spot! fseeko would return an error, but this error is ignored.
On pcap_ng_open_offline returning an error, Apple's patch then calls pcap_open_offline, which follows a similar control flow to normal pcap. However, because the file pointer on the FIFO is still forward by 4 bytes, the next set of headers have the fifo's magics, and so tcpdump gives up.
You can work around this by inserting 4 extra NULL bytes at the start of your pipe, with a little shell-script trickery:
tcpdump -i en0 -w - | cat <(printf "\0\0\0\0") - | tcpdump -nvr -
This means that when fseeko fails, you'll be in the correct spot in the FIFO for the "actual" magic.
However, there are still some limitations:
tcpdump -P (Apple-specific pcapng flag) still doesn't work.
- These files are no longer valid
pcap files. If you wanted to read it with another tool (or even a non-Apple tcpdump), you'll need to tee the output before cat.
This also works with tshark (which can output pcapng, and doesn't work as a source without this work-around):
tshark -F pcapng -w - | cat <(printf "\0\0\0\0") - | tcpdump -nvr -
However, I wouldn't suggest putting this work-around in anything long term.
It will break once Apple fixes this bug, or if your users have a non-Apple tcpdump on OSX (such as with Homebrew).