tcpdump
tcpdump copied to clipboard
Reading from stdin while dumping to file causes crash
Converted from SourceForge issue 3602279, submitted by toreanderson
When attempting to reading from stdin and dumping the result to a capture file, the process crashes almost instantly. An easy way to reproduce this, is:
computer$ nc -l 12345 | tcpdump -r- -v -wfoo.pcap reading from file -, link-type EN10MB (Ethernet) tcpdump: pcap_loop: error reading dump file: Interrupted system call write: Broken pipe
If I omit the "-wroo.pcap" option, it works just fine, decoded traffic is printed to stdout just as expected and no crashes are experienced.
The version used is the one included in Fedora 18: tcpdump-4.3.0-2.fc18.x86_64.
The PCAP stream coming in on 12345/tcp to the nc process is a tcpdump running on another machine like so: "tcpdump -i eth1.3900 -s0 -w- -U ip6 | nc computer 12345".
This reproduces on the current master branch on a Linux host.
To quote a comment in tcpdump.c:
/*
* When capturing to a file, "-v" means tcpdump should,
* every 10 secodns, "v"erbosely report the number of
* packets captured.
*/
In most cases, -v isn't useful when reading from a file and writing to a file, rather than when capturing from a device and writing to a file; however, there's probably no harm in supporting it - if you don't want that output, don't specify -v.
In this case, it might be more useful, as you are, in effect, capturing from the other machine.
Therefore, we need to do something with EINTR when reading packets. Obviously, if it was interrupted by SIGINT (^C), we should quit, but if it was interrupted by SIGALRM (the timer for -v when writing to a file), we should just keep reading.
This will require libpcap changes - merely setting the SA_RESTART flag for SIGALRM means that, instead of getting "Interrupted system call", we get "truncated dump file; tried to read 300 captured bytes, only got 170". At least when reading from a pipe, we need to keep reading bytes until we get an EOF.
See also the-tcpdump-group/libpcap#1258.
Naively, since we're only setting the callback when using -w, can't this be implemented in dump_packet()
instead? If enough time has passed, then call print_packets_captured()
, and don't set the itimer at all?
If there is a difficult to fix reason for once per second counter update not to work when reading from a file, let's enable the counter for live captures only and document the behaviour. This would resolve the corner case crash; if anybody wants to make it perfect later, they can propose a patch.
I naively suggested:
Naively, ... can't this be implemented in
dump_packet()
instead?
Obviously there's a significant difference in that, if you get 1000 packets in the first 0.9 seconds, and then no more, the counter will never update. (The use case that I'm interested in is sflowtool, which converts sflow-format captured packets to pcap, so libpcap will block regularly.)
infrastation said:
let's enable the counter for live captures only and document the behaviour
This is obviously the best short-term approach.
Do you think a separate thread around print_packets_captured()
would be easier to implement? Would it still be portable enough?
Do you think a separate thread around
print_packets_captured()
would be easier to implement? Would it still be portable enough?
I've always tried to avoid threads in portable code, but I don't have an educated opinion here, more just a mystical one :-)
The master branch of tcpdump now has a documented safeguard with comments as discussed above. @guyharris, is signal handling in libpcap you described earlier still an important enough problem to state/document it elsewhere and maybe to work on a solution?