значения длины пакета pcap кажутся неправильными - PullRequest
2 голосов
/ 05 февраля 2012

Я пишу приложение C, которое использует библиотеку pcap для регистрации того, сколько данных (соответствующих различным пакетным фильтрам) прошло через сетевую карту.Значения, которые я получаю, кажутся слишком низкими, чтобы быть правильными, но я не уверен, что делаю неправильно.

Тестовый код ниже демонстрирует то же поведение (проверка ошибок для ясности опущена):

#include <stdio.h>
#include <pcap.h>

static int total=0;
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data){
    total += header->len;
    printf("%d\n", total);
}

int main(){
    char errbuf[1024];

    pcap_t *adhandle = pcap_open_live("en1", 65535, 0, 0, errbuf);
    pcap_setnonblock(adhandle, 1, errbuf);
    struct bpf_program fcode;
    pcap_compile(adhandle, &fcode, "port 80", 1, 0);
    pcap_setfilter(adhandle, &fcode);

    while(1){
        pcap_dispatch(adhandle, -1, packet_handler, NULL);
        sleep(1);
    }
    return 0;
}

Я работаю над OSX, собираю с помощью gcc, и я попытался загрузить через Wi-Fi и проводной Ethernet.Я ожидаю, что приведенный выше код распечатает количество байтов, которые соответствуют фильтру (в данном случае весь трафик HTTP), но когда я загружаю тестовый файл размером 4 357 017 байт, я получаю значение только 95 133.Мой тестовый файл представлял собой zip-архив, поэтому я не думаю, что HTTP-сжатие может объяснить разницу.

Обновление: Я изменил код, чтобы распечатать размер каждого пакета,а также промежуточный итог, а также сообщать только о входящих пакетах (изменил фильтр на «порт src 80»).Это дает много длин пакетов «1514», что, я думаю, связано со значением MTU 1500, однако общее количество остается слишком низким.

1 Ответ

2 голосов
/ 06 февраля 2012

Здесь нет никакой гарантии, что ваша программа видит все пакеты;если он их не видит, он не может их сосчитать, и в этом случае не удивительно, что сумма длин захваченных пакетов была меньше количества передаваемых данных.

Прежде всегоВы не должны использовать неблокирующий режим, если ваша программа не делает нечто большее, чем просто захват пакетов - опрос здесь не работает лучше, он может работать хуже.С вашим кодом система будет исчерпывать пространство буфера BPF, если в секунду поступит больше пакетов, чем помещается в буфер, то есть пакеты будут отброшены, и ваша программа никогда их не увидит и, следовательно, не будет их считать.До Lion размер буфера по умолчанию составлял около 32K или около того, что означает, что есть очень хороший шанс, что система может исчерпать пространство буфера BPF;Lion выбирает изменение libpcap 1.1, чтобы размер буфера по умолчанию для систем BPF составлял 512 КБ, так что это вряд ли произойдет, но вы все равно не должны использовать неблокирующий режим, если вам действительно это не нужно.*

Кроме того, вы не должны использовать неблокирующий режим вообще на Snow Leopard, так как в коде ядра BPF в Snow Leopard есть ошибка (FreeBSD-версия ошибки PR 143855 );его нет в Leopard или ранее (он был введен в исправлении ошибки, исправленной в Snow Leopard), и исправлен в Lion.

Итак, первое, что я хотел бы сделать, это избавиться отpcap_setnonblock(adhandle, 1, errbuf); call и sleep(1); call, чтобы ваша программа обрабатывала пакеты так быстро, как только могла.

Кроме того, если она не должна работать на Leopard (в которой была более старая версия libpcapкоторый не поддерживает pcap_create() или pcap_activate()), я бы увеличил размер буфера до 512 Кб, выполнив (проверка ясности удалена для ясности):

adhandle = pcap_create("en1", errbuf);
pcap_set_buffer_size(adhandle, 524288);
pcap_activate(adhandle);

Наконец, я бы получил вашу программукаким-то образом предоставьте способ сообщить, когда следует прекратить захват, и, когда он остановится, заставить его вызвать pcap_stats() и сообщить о количестве отброшенных пакетов, чтобы вы могли определить, были ли отброшены какие-либо пакеты.

...