Асинхронный 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. Пожалуйста, смотрите мой другой вопрос для сведения.