看板 DFBSD_bugs 關於我們 聯絡資訊
--Apple-Mail-2--19444588 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii Non-blocking reads from a BPF device not in immediate mode will not = rotate the buffers even if there's data in the store buffer but not in = the hold buffer, so, until the store buffer fills up, the reads will = return -1 and set errno to EWOULDBLOCK. To reproduce, compile the attached (C++) program, run it on an adapter = with the filter "icmp" on a reasonably quiet network, and then, on the = same machine, ping some host the pings to which will go out on the same = network. Note that the program doesn't report any packets having been = seen. To fix, apply the attached patch. (A similar bug has been filed against = FreeBSD - and will be filed against Mac OS X.) --Apple-Mail-2--19444588 Content-Disposition: attachment; filename=libpcaptest.cpp Content-Type: application/octet-stream; name="libpcaptest.cpp" Content-Transfer-Encoding: 7bit #include <iostream> #include <stdio.h> #include <string> #include <vector> #include <errno.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/time.h> #include <net/bpf.h> #include <pcap.h> pcap_t* create(const std::string& name, const std::string& pcapFilter, uint32_t snapLen, bool promisc); bool capture(pcap_t * pcapSession); void close(pcap_t* pcapSession); int main(int argc, char** argv) { if (argc != 3) { std::cerr << "Usage: libpcaptest <interface> <filter>" << std::endl; return 1; } std::string name(argv[1]), filter(argv[2]); std::cout << "Capturing from '" << name << " with filter " << filter << std::endl; pcap_t * pcapSession = create(name, filter, 128, true); capture(pcapSession); close(pcapSession); return 0; } /** This is the callback **/ void test_pcap_handler(u_char* user, const struct pcap_pkthdr* header, const u_char* pkt_data) { std::cout << "Packet captured" << std::endl; } /** Temporary used since on Windows they forgot to sign as 'const char*' the filter string provided to pcap_compile... **/ void duplicateFilterString(const std::string& pcapFilter, std::vector<char>& dupFilter) { dupFilter.clear(); dupFilter.resize(pcapFilter.size()+1, 0); for (uint32_t i=0; i<pcapFilter.size(); ++i) dupFilter[i] = pcapFilter[i]; } void close(pcap_t* pcapSession) { if (pcapSession) { pcap_close(pcapSession); } } pcap_t* create(const std::string& name, const std::string& pcapFilter, uint32_t snapLen, bool promisc) { char errbuf[PCAP_ERRBUF_SIZE]; pcap_t* pcapSession; if ((pcapSession = pcap_open_live(name.c_str(), snapLen, promisc ? 1 : 0, 1000, errbuf)) == NULL) { std::cerr << "Failed pcap_open_live because <" <<errbuf<<">" << std::endl; return NULL; } // compile the filter if it's been supplied or snapLen is provided if (pcapFilter.empty()==false || snapLen<65535) { // get netmask bpf_u_int32 pcapNetaddr, pcapMask; pcap_lookupnet(name.c_str(), &pcapNetaddr, &pcapMask, errbuf); struct bpf_program pcapFilterProgram; std::vector<char> filterDup; duplicateFilterString(pcapFilter, filterDup); if (pcap_compile(pcapSession, &pcapFilterProgram, &filterDup[0], 1, pcapMask) == -1) { std::string error = pcap_geterr(pcapSession); pcap_close(pcapSession); std::cerr << "Failed pcap_compile because <" <<errbuf<<">" << std::endl; return NULL; } if (pcap_setfilter(pcapSession, &pcapFilterProgram) == -1) { std::string error = pcap_geterr(pcapSession); pcap_freecode(&pcapFilterProgram); pcap_close(pcapSession); std::cerr << "Failed pcap_setfilter because <" <<errbuf<<">" << std::endl; return NULL; } pcap_freecode(&pcapFilterProgram); } // set session in non blocking mode if (pcap_setnonblock(pcapSession, 1, errbuf)!=0) { pcap_close(pcapSession); std::cerr << "Failed pcap_setnonblock because <" <<errbuf<<">" << std::endl; return NULL; } /* Enable this for immediate delivery of packets through callback. uint32_t v = 1; if (ioctl(pcap_fileno(pcapSession), BIOCIMMEDIATE, &v) < 0) { pcap_close(pcapSession); std::cerr << "Failed ioctl BIOCIMMEDIATE" << std::endl; return NULL; } */ int dlt; const char *dlt_name; dlt = pcap_datalink(pcapSession); dlt_name = pcap_datalink_val_to_name(dlt); if (dlt_name == NULL) { (void)fprintf(stderr, "listening on %s, link-type %u, capture size %u bytes\n", name.c_str(), dlt, snapLen); } else { (void)fprintf(stderr, "listening on %s, link-type %s (%s), capture size %u bytes\n", name.c_str(), dlt_name, pcap_datalink_val_to_description(dlt), snapLen); } return pcapSession; } bool capture(pcap_t * pcapSession) { struct pcap_stat pcapStats; while (true) { int32_t ret = pcap_dispatch(pcapSession, 100, test_pcap_handler, (u_char*)NULL); std::cout << "Read " << ret << " packets" << std::endl; if (pcap_stats(pcapSession, &pcapStats) != 0) { std::string error = pcap_geterr(pcapSession); std::cerr << "Failed pcap_setnonblock because <" <<error<<">" << std::endl; return false; } std::cout << "ReceivedPackets " << pcapStats.ps_recv << " DroppedPackets " << pcapStats.ps_drop << " I/F DroppedPackets " << pcapStats.ps_ifdrop << std::endl; if (ret==-1) { std::string error = pcap_geterr(pcapSession); std::cerr << "Failed pcap_dispatch because <"<<error<<">" << std::endl; return NULL; } sleep(5); } return true; } --Apple-Mail-2--19444588 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii --Apple-Mail-2--19444588 Content-Disposition: attachment; filename=patch.txt Content-Type: text/plain; name="patch.txt" Content-Transfer-Encoding: 7bit --- bpf.c.orig 2010-02-13 00:31:52.000000000 -0800 +++ bpf.c 2010-02-13 00:33:32.000000000 -0800 @@ -421,9 +421,12 @@ * have arrived to fill the store buffer. */ while (d->bd_hbuf == NULL) { - if ((d->bd_immediate || timed_out) && d->bd_slen != 0) { + if ((d->bd_immediate || (ap->a_ioflag & IO_NDELAY) || timed_out) + && d->bd_slen != 0) { /* - * A packet(s) either arrived since the previous + * We're in immediate mode, or are reading + * in non-blocking mode, and a packet(s) + * either arrived since the previous * read or arrived while we were asleep. * Rotate the buffers and return what's here. */ --Apple-Mail-2--19444588--