Некоторая ошибка в коде - libpcap - PullRequest
1 голос
/ 14 февраля 2012

Я пытаюсь проанализировать файл pcap в C. Я не хочу использовать libpcap.Но по какой-то причине я не могу.Вы знаете, как я могу это сделать?Вот моя попытка:

fseek(f,24,0);
while(count<20)//reading 20 packets
{ 
  fread(header,sizeof(struct pcap_pkthdr),1,f);
  //after this I'm printing values header fields
  fseek(f,ntohl(header->caplen),1);
  count++;
}

Вывод не совпадает с libpcap.

Ответы [ 3 ]

4 голосов
/ 15 февраля 2012

struct pcap_pkthdr - это НЕ структура, которая определяет формат заголовков пакетов в файле pcap; это структура, которая определяет формат заголовков пакетов, предоставляемый программам, использующим libpcap или WinPcap.

Структура, которая определяет формат заголовков пакетов в файле pcap, NOT в любом из включаемых файлов pcap, поскольку libpcap / WinPcap предоставляет подпрограммы, которые читают эти заголовки и преобразуют их при необходимости в * 1008. * заголовки. В отличие от struct pcap_pkthdr отметка времени в заголовках пакетов в файле pcap всегда имеет 32-битное поле «секунд» и 32-битное поле «микросекунд», даже в системах, где time_t и значение tv_sec в struct timeval - это 64 бита.

Т.е. структура определяется

struct pcap_timeval {
    bpf_int32 tv_sec;           /* seconds */
    bpf_int32 tv_usec;          /* microseconds */
};


struct pcap_sf_pkthdr {
    struct pcap_timeval ts;     /* time stamp */
    bpf_u_int32 caplen;         /* length of portion present */
    bpf_u_int32 len;            /* length this packet (off wire) */   
};

где struct pcap_sf_pkthdr - структура в файле.

Обратите внимание, что если вы читаете struct pcap_sf_pkthdr из файла, вам придется поменять местами ts.tv_sec, ts.tv_usec, caplen и len IF файл был написан на машине, чей порядок байтов отличается от машины, на которой вы читаете файл. Что-то столь же простое, как ntohl(), будет НЕ работать - если, например, ваш файл был записан на той же машине, что и тот, на котором вы его читаете, обмен байтами не требуется.

ONLY способ заставить эту работу заключаться в READ заголовке файла, а не просто пропускать его с помощью fseek(). Если «магическое число» в заголовке файла имеет значение 0xa1b2c3d4, то вам не нужно делать никакой замены байтов; если оно имеет значение 0xd4c3b2a1, вам нужно будет поменять местами значения в заголовке файла и struct pcap_sf_pkthdr. Обратите внимание, что ntohl() и htonl() будут НЕ байт-своп, если вы работаете на машине с прямым порядком байтов, такой как машина PowerPC / Power Architecture или машина MIPS, мэйнфрейм IBM или ... ..

Обратите внимание, что не все файлы захвата будут файлами pcap; если это файлы pcap-NG, их нужно читать совершенно по-другому. Libpcap 1.1 и более поздние версии знают, как читать файлы pcap-NG (API libpcap / WinPcap недостаточно мощен для обработки всех файлов pcap-NG, но он может, например, обрабатывать файлы pcap-NG, которые иметь только один раздел и иметь пакеты только от одного сетевого адаптера, и libpcap 1.1 и более поздние могут их читать). Я бы посоветовал, как и предполагали, использовать libpcap / WinPcap для чтения файлов захвата, а не писать собственный код для этого.

1 голос
/ 14 февраля 2012

Убедитесь, что вы правильно обрабатываете порядок файлов формата pcap.

Кроме того, прямая загрузка целых структур с диска редко безопасна, поскольку компиляторы могут свободно вставлять заполнение между полями структуры, что приведет кбайты с диска не совпадают с байтами в памяти.

Я бы посоветовал вам использовать официальную библиотеку, так как об этих проблемах уже позаботятся.

0 голосов
/ 14 февраля 2012

Попробуйте что-то подобное:

struct dump_pcap_pkthdr {
struct          timeval ts; /* time stamp */
unsigned int    caplen;     /* length of portion present */
unsigned int    len;        /* length this packet (off wire) */
};

struct dump_pcap_file_header {
unsigned int    magic;
unsigned short  version_major;
unsigned short  version_minor;
int             thiszone;   /* gmt to local correction */
unsigned int    sigfigs;    /* accuracy of timestamps */
unsigned int    snaplen;    /* max length saved portion of each pkt */
unsigned int    linktype;   /* data link type (LINKTYPE_*) */
};


static void read_pcap_file(char *file)
{
int fd    = -1;
struct dump_pcap_pkthdr packet_header    = {0};
struct dump_pcap_file_header pcap_header = {0};

fd = open(file, O_RDONLY);
if(fd < 0) {
    printf("Fail open file: %s\n", file);
    return;
}

if(read(fd, &pcap_header, sizeof(pcap_header)) != sizeof(pcap_header)) {
    printf("Failed to read TCPDump Header from file: %s\n", file);
    return;
}

while(1)
{
    r = read(fd, &packet_header, sizeof(packet_header));
    if(r != sizeof(packet_header))
        break;

    //print data           

    lseek(fd, packet_header.caplen, SEEK_CUR);
}

close(fd);
}
...