Можно ли анализировать пакеты pcap из буфера

У меня есть куча огромных файлов pcap (> 10 ГБ), сжатых с помощью lzma. Мне нужно разобрать их на моей машине, и у меня недостаточно места, чтобы сначала распаковать их. Есть много библиотек, которые могут передавать lzma из файла. Проблема на стороне libpcap, я несколько раз читал его API и не смог найти способ разобрать буфер. Что я вижу в исходном коде libs, так это то, что он сначала читает магический байт и заголовок файла с fread:

    amt_read = fread((char *)&magic, 1, sizeof(magic), fp);
    ...
    amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1, sizeof(hdr) - sizeof(hdr.magic), fp);

А затем pcap_next_packet также использует fread для чтения следующего пакета из файла. Таким образом, похоже, что ему сложно передать буфер из потока lzma. С другой стороны, эти функции хранятся в структура pcap_t в виде указателей. Таким образом, я могу реализовать для него свои собственные процедуры, однако таким образом мне придется дублировать много кода из libpcap. Кто-нибудь знает, как это сделать без взлома libpcap?

Я что-то упустил в API libpcap?

Обновление: с помощью @Martin и других мне удалось заставить его работать. Я опубликую реализацию, чтобы люди, которые ищут способ сделать это, могли ее использовать.

if (check_file_exists("/path/to/file.pcap.xz")) {
    return;
}
// first open a pipe
FILE *pipe = popen("xz -d -c /path/to/file.pcap.xz", "r");
if (!pipe) {
    // handle error somehow
    return;
}
char errbuff[256];
// note pcap_fopen_offline function that takes FILE* instead of name
pcap_t *pcap = pcap_fopen_offline(pipe, errbuff);
struct pcap_pkthdr *header;
uint8_t *data;
while (pcap_next_ex(pcap, &header, &data)) {
    // handle packets
}

person Pavel Davydov    schedule 20.09.2017    source источник
comment
Возможно, вы сможете использовать именованный канал.   -  person Steve Summit    schedule 20.09.2017
comment
@SteveSummit Я думал об этом, однако боюсь, что это замедлит работу приложения: данные из pcap будут сначала скопированы в ядро, затем снова скопированы в пространство пользователя, больше системных вызовов и т. д.   -  person Pavel Davydov    schedule 20.09.2017
comment
@SteveSummit Кстати, вы знаете какой-нибудь инструмент, который может анализировать pcap из канала? Может быть, я могу найти ответ в его исходном коде.   -  person Pavel Davydov    schedule 20.09.2017
comment
Что именно вы хотите разобрать? Сам формат файла pcap очень прост и ясен, возможно, вам даже не нужен libpcap для того, чего вы пытаетесь достичь.   -  person Ctx    schedule 20.09.2017
comment
@Ctx Я хочу анализировать пакеты UDP из pcap. Было бы идеально, если бы какая-нибудь библиотека могла анализировать заголовки UDP и просто давать мне свою полезную нагрузку, однако я могу справиться с этим и в своем приложении. По крайней мере, я хочу разобрать пакеты. Я читал, что формат pcap прост и состоит из заголовка файла и заголовка пакета, однако после проверки исходного кода libpcap я подумал, что в нем есть много угловых случаев, которые каким-то образом обрабатываются в библиотеке. Считаете ли вы, что анализировать его без pcap - хорошая идея?   -  person Pavel Davydov    schedule 20.09.2017
comment
Существует множество крайних случаев при захвате в реальном времени с сетевых интерфейсов или когда задействовано множество различных протоколов уровня 2. Но я не вижу никаких трудностей при разборе pcap-файла вручную, который обычно всегда имеет один и тот же протокол уровня 2 (например, Ethernet).   -  person Ctx    schedule 20.09.2017
comment
Почти всегда лучше использовать официальную библиотеку для чтения и анализа форматированных данных из файла или потока. Заявление о том, что официальная библиотека по какой-то причине неадекватна и что вам придется создавать свою собственную, почти всегда приводит к разочарованию в будущем. (И я говорю это как человек, который всегда качает свои собственные программы для чтения файлов, потому что официальные всегда в чем-то неадекватны.)   -  person Steve Summit    schedule 20.09.2017
comment
@SteveSummit Ха, спасибо за хороший совет :)   -  person Pavel Davydov    schedule 20.09.2017


Ответы (1)


В частности, для больших файлов pcap предпочтительнее не считывать их целиком в память. Чтобы правильно управлять буфером, вам нужно понять формат pcap, чтобы получить правильные длины и т. д.

Вы можете транслировать его с помощью popen, например:

char* cmd = asprintf("/usr/bin/xz -d -c %s", filename);
FILE* fp = popen(cmd , "r");
free(cmd);

Затем прочитайте из fp так же, как если бы он был несжатым. Вы также можете сделать функцию-оболочку для open, возвращающую FILE*, которая решает, следует ли передавать его через различные декомпрессоры по расширению или просто выполнить простой fopen.

В общем, я считаю, что обычные каналы предпочтительнее именованных каналов, где это возможно, поскольку это экономит (а) выбор уникального имени и (б) очистку их во всех случаях ошибок.

Или просто проанализируйте pcap вручную, формат довольно тривиален, IIRC — это всего лишь одна структура заголовка, затем по одной на пакет.

person lunix    schedule 20.09.2017
comment
Это не сильно отличается от предложения именованного канала (которое проще реализовать, потому что основной программе нужно только читать, чтобы читать из (именованного) файла.) В обоих случаях ввод не будет доступен для поиска. - person wildplasser; 20.09.2017
comment
Спасибо за предложение. Я попробую, однако я не уверен, насколько ухудшится производительность по сравнению с разбором буфера в памяти. - person Pavel Davydov; 20.09.2017
comment
@wildplasser Требует ли libpcap доступ к файлу для поиска? - person Pavel Davydov; 20.09.2017
comment
Если у вас более 1 ЦП, это, вероятно, быстрее, так как вы разгружаете распаковку на другое ядро. - person lunix; 20.09.2017
comment
Я не знаю. Вы могли бы проверить источник. (теоретически это не нужно) Источник, на который вы ссылаетесь как минимум, содержит SEEK_END. - person wildplasser; 20.09.2017
comment
@Martin: ты имеешь в виду быстрее, чем что? - person wildplasser; 20.09.2017
comment
@wildplasser Ну, у него есть несколько fseeks в функции дампа (я все равно не собираюсь делать дамп в канал), с другой стороны в этом комментарии говорится, что каналы поддерживаются. - person Pavel Davydov; 20.09.2017
comment
Что ж, тогда начните с предложения @SteveSummit. Вот аналогичное использование именованного канала/fifo: stackoverflow.com/a/41741644/905902 - person wildplasser; 20.09.2017
comment
быстрее, чем использовать библиотеку распаковки внутри той же задачи, а затем анализировать буфер. Кроме того, в целом я считаю, что каналы предпочтительнее именованных каналов, где это возможно, поскольку это экономит (а) выбор уникального имени и (б) очистку их во всех случаях ошибок. - person lunix; 20.09.2017
comment
Что ж, если я выберу трубы, я воспользуюсь решением @Martin. Именованные каналы в целом были бы проще, однако в моем приложении есть состояние внутри, поэтому оно должно обрабатывать каналы от себя, и таким образом проще использовать popen. - person Pavel Davydov; 20.09.2017
comment
Я отметил это как ответ, если в моем случае работает трюк с трубой. В вопрос добавлен пример кода, использующего канал с pcap. Спасибо @Мартин. - person Pavel Davydov; 21.09.2017