Асинхронный libpcap: потеря пакетов?

у меня есть программа, которая отправляет набор пакетов TCP SYN на хост (используя необработанные сокеты) и использует libpcap (с фильтром) для получения ответов. Я пытаюсь реализовать это в асинхронной структуре ввода-вывода, но кажется, что libpcap отсутствуют некоторые ответы (а именно первые пакеты серии, когда требуется меньше 100 microseconds между TCP SYN и ответом). Ручка pcap настроена следующим образом:

pcap_t* pcap = pcap_open_live(NULL, -1, false, -1, errorBuffer);
pcap_setnonblock(pcap, true, errorBuffer);

затем я добавляю фильтр (содержащийся на строка filterExpression):

struct bpf_program filter;
pcap_compile(pcap, &filter, filterExpression.c_str(), false, 0);
pcap_setfilter(pcap, &filter);
pcap_freecode(&filter);

и в цикле, после отправки каждого пакета, я использую select, чтобы узнать, могу ли я читать из libpcap:

int pcapFd = pcap_get_selectable_fd(pcap);
fd_set fdRead;
FD_ZERO(&fdRead);
FD_SET(pcapFd, &fdRead);
select(pcapFd + 1, &fdRead, NULL, NULL, &selectTimeout);

и прочел:

if (FD_ISSET(pcapFd, &fdRead)) {
     struct pcap_pkthdr* pktHeader;
     const u_char* pktData;
     if (pcap_next_ex(pcap, &pktHeader, &pktData) > 0) {
         // Process received response.
     }
     else {
         // Nothing to receive (or error).
     }
}

как я уже говорил, некоторые из пакетов пропущены (попадая в "ничего, чтобы получить" еще). Я знаю, что эти пакеты есть, потому что я могу захватить их синхронным способом (используя tcpdump или поток работает pcap_loop). Я упускаю какую-то деталь? Или это проблема с libpcap?

2 ответов


если FD для pcap_t как читается по select() (или poll() или любой вызов / механизм, который вы используете), нет никакой гарантии, что это означает, что только один пакет может быть прочитан без блокировки.

если вы используете pcap_next_ex(), вы будете читать только один пакет; если есть несколько пакетов, доступных для чтения, то, если вы делаете другой select(), он должен немедленно вернуться, сообщив, что FD снова читается, и в этом случае вы предположительно вызовете pcap_next_ex() снова и так далее. Это означает, по крайней мере, один системный вызов на пакет (select()) и, возможно, больше вызовов, в зависимости от того, какую версию какой ОС вы делаете и какую версию libpcap у вас есть.

если вместо этого вы позвоните pcap_dispatch(), С аргументом подсчета пакетов -1, этот вызов вернет все пакеты, которые могут быть получены с помощью одной операции чтения, и обработает их все, поэтому на большинстве платформ вы можете получить несколько пакетов с одним или двумя системными вызовами, если есть доступно несколько пакетов (что, с высоким сетевым трафиком, как вы могли бы получить, если вы тестируете свою программу с потоком SYN, вероятно, будет иметь место).

кроме того, в системах Linux, поддерживающих захват пакетов с отображением памяти (я думаю, что все ядра 2.6 и более поздних версий, и большинство, если не все ядра 2.4), и с более новыми версиями libpcap,pcap_next_ex() должен сделать копию пакета, чтобы ядро не изменило пакет из-под кода, обрабатывающего пакет, и в избегайте "блокировки" слота в кольцевом буфере в течение неопределенного периода времени, поэтому есть дополнительная копия.


Это, похоже, проблема с libpcap с использованием сопоставления памяти под Linux. Пожалуйста, смотрите мой другой вопрос для сведения.