tcpdump mailing list archives
Bug in libpcap: savefile.c / get_selectable_fd()
From: "Shaked, Nitzan" <nshaked () paypal com>
Date: Tue, 17 Mar 2009 22:33:36 -0000
Hello all I hope this mailing list is active, and that this is the right place to post to. In any case, I believe I have discovered a bug: get_selectable_fd() does not work well when used with pcap_open_offline(). The symptom is that if you use, as was the poet's intention, get_selectable_fd()'s return value in a call to select() and then use pcap_next() to get a packet, you will fail to read the last few packets if reading from a pipe (for example: reading from stdin when it's piped). The reason is that savefile.c implements the read_op using fread, which is stdio and uses *buffering*, while select() is kernel IO and is unaware of the buffers in stdlib. So while the last packets are inside stdlib's buffer, select() will not see the fd as "ready for read", will never return, and you will never see these packets. (Assume that the pipe doesn't close -- it stays open but simply has no more input. For example: it's the output of tcpdump -w) In general, it's a bad thing to mix buffered IO (stdlib, such as fread,fread,fseek, etc) with kernel io (read/write/seek/select, etc). There are 2 obvious solutions, with pros and cons each, and possibly more solutions as well: 1) Use setvbuf( fp, NULL, _IONBF, 0 ) inside pcap_fopen_offline. I tried this and it works, on both Solaris and Red-Hat. There are several drawbacks which I will detail later. 2) Stop using stdlib in savefile.c: use read instead of fread. There are only a handful of places to change, and it seems easy enough. The "downsize" is that you can't simply replace a call to fread with a call to read, because read() may be interrupted, so you need to loop if you get EINTR. Another downside is that you have to remove pcap_fopen_offline(), and replace it with something like pcap_fdopen_offline(). Again: no stdio at all. The downsides for (1) above: a) setvbuf(), in glibc, does what you want:removes buffers *also from the input, that is: if you use fread()*. It is *NOT* guaranteed to be the case in the official stdio documentation. All the documentation I found only talks about fwrite() and flushing. So it works for glibc, but maybe not for other stdio libs. b) The documentation states that you must call setvbuf() prior to doing any IO on the FILE* object (but after having fopen'ed it, of course). In pcap_fopen_offline() we don't know whether somebody has done any IO on the FILE* object we are passed. It works well in glibc, again, because it zeros its read pointer, write point, in buf, out buf, the works. It may not, again, work well in other stdio libs, or may not work well if we've done some reading which is still buffered (but not consumed) even in glibc. It *does* work well if you, right on program start, try to pcap_open_offline( "-", errbuf ) without reading from stdin, but that's the only case I checked. ... so: distinguished forum: what do you think? Is the description enough? Should I provide a patch? Should I open a bug in sf.net? Best, Nitzan - This is the tcpdump-workers list. Visit https://cod.sandelman.ca/ to unsubscribe.
Current thread:
- Bug in libpcap: savefile.c / get_selectable_fd() Shaked, Nitzan (Mar 17)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Guy Harris (Mar 17)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Guy Harris (Mar 17)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Shaked, Nitzan (Mar 19)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Guy Harris (Mar 19)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Shaked, Nitzan (Mar 19)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Shaked, Nitzan (Mar 22)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Guy Harris (Mar 17)