Apple - Why does tcpdump not recognise piped input?

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

Tags:

Command Line