[dns-operations] Open source release of the DNS-STATS Compactor
Jim Hague
jim at sinodun.com
Thu Jun 22 11:08:07 UTC 2017
On 21/06/2017 17:28, Robert Edmonds wrote:
> Jim Hague wrote:
>> Yes, I did verify that it's not a libtins problem. I reproduced the
>> problem with a small libpcap-only program. However, I think that it is
>> in fact a kernel problem rather than libpcap.
>>
>> Also, it's only a problem when using pacp_next()/pcap_next_ex() or
>> pcap_dispatch(). It doesn't manifest with pcap_loop(), which is why I
>> think tcpdump works.
>
> Any chance you could share that libpcap test program? That sounds like a
> pretty serious bug. The Debian Jessie release is still supported by the
> Debian project, so if that problem is due to a kernel or libpcap bug it
> would be nice to get it fixed in an update.
No problem. Attached. I'm building with:
$ g++ -std=c++11 -o test_pcap test_pcap.cpp -lpcap
When run on a 14.04.5 install with the linux-image-generic kernel, as below:
jim at trusty:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.5 LTS
Release: 14.04
Codename: trusty
jim at trusty:~$ uname -a
Linux trusty 3.13.0-121-generic #170-Ubuntu SMP Wed Jun 14 09:04:33 UTC
2017 x86_64 x86_64 x86_64 GNU/Linux
or a Debian Jessie install:
jim at jim-dev-debian:~/Develop/src/dns-cap-cpp/src$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 8.8 (jessie)
Release: 8.8
Codename: jessie
jim at jim-dev-debian:~/Develop/src/dns-cap-cpp/src$ uname -a
Linux jim-dev-debian 3.16.0-4-amd64 #1 SMP Debian 3.16.43-2+deb8u1
(2017-06-18) x86_64 GNU/Linux
$ sudo ./test_pcap loop <interface>
will show packets being received as expected from external input, e.g.
$ ping -c 5 -i 0.2 <jessie host>
Re-run the test as
$ sudo ./test_pcap dispatch <interface>
and you won't see the expected number of packets. It looks to me that if
there's more a gap of about 50 milliseconds or more between packets,
you'll lose the first packet after the gap.
Judging by the timing of the printed output, a waiting select() on the
PCAP handle exits on receipt of a new packet, but a subsequent call to
to pcap_next_ex() or pcap_dispatch() does not find the packet.
A fresh 14.04.5 install will install linux-image-generic-lts-xenial, not
linux-image-generic. I believe this has been the case since 14.04.2. I
see no problems with this kernel series, or with Xenial installs.
--
Jim Hague - jim at sinodun.com Never trust a computer you can't lift.
-------------- next part --------------
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <pcap/pcap.h>
#include <sys/select.h>
void error(const char* msg)
{
std::perror(msg);
std::exit(1);
}
void usage()
{
std::cerr << "Usage: test_pcap [-n|--non-blocking] next|dispatch|loop <interface>\n";
std::exit(1);
}
void dispatcher(u_char *user, const struct pcap_pkthdr* h, const u_char* bytes)
{
static int no_read = 0;
std::cout << "Read packet " << ++no_read << std::endl;
}
int main(int ac, char *av[])
{
bool non_blocking = false;
if ( ac < 3 || ac > 4 )
usage();
ac--;
av++;
std::string arg(*av);
if ( arg == "-n" || arg == "--non-blocking" )
{
non_blocking = true;
ac--;
av++;
if ( ac < 2 )
usage();
arg = *av;
}
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t* handle = pcap_create(av[1], errbuf);
if ( !handle )
error(av[1]);
if ( pcap_set_snaplen(handle, 65535) != 0 )
error("snaplen");
if ( pcap_activate(handle) < 0 )
error("activate");
if ( non_blocking && pcap_setnonblock(handle, 1, errbuf) < 0 )
error("nonblock");
int fd = pcap_get_selectable_fd(handle);
if ( fd < 0 )
error("selectable");
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
for(;;)
{
if ( arg == "next" )
{
struct pcap_pkthdr* hdr;
const u_char* data;
bool read_one;
do
{
read_one = false;
std::cout << "Reading..." << std::endl;
switch (pcap_next_ex(handle, &hdr, &data))
{
case 1:
read_one = true;
dispatcher(nullptr, nullptr, nullptr);
continue;
case 0:
std::cout << "Nothing read" << std::endl;
break;
default:
error("packet read");
break;
}
} while ( read_one );
}
else if ( arg == "dispatch" )
{
std::cout << "Dispatching..." << std::endl;
pcap_dispatch(handle, -1, dispatcher, nullptr);
}
else if ( arg == "loop" )
{
std::cout << "Looping..." << std::endl;
pcap_loop(handle, -1, dispatcher, nullptr);
}
else
usage();
fd_set fd_selected = fdset;
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
switch (select(fd + 1, &fd_selected, nullptr, nullptr, &tv))
{
case -1:
switch(errno)
{
case EAGAIN:
case EINTR:
break;
default:
error("select");
break;
}
default:
break;
}
}
}
More information about the dns-operations
mailing list