简体   繁体   中英

Some error in the code - libpcap

I'm trying to parse a pcap file in C. I don't want to use libpcap. But for some reason, I'm unable to. Do you know how can I do this ? Here is my attempt :

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++;
}

Output is not the same as libpcap.

struct pcap_pkthdr is NOT the structure that defines the format of packet headers in a pcap file; it's the structure that defines the format of packet headers as provided to programs using libpcap or WinPcap.

The structure that defines the format of packet headers in a pcap file is NOT in any of the pcap include files, because libpcap/WinPcap provides routines that read those headers and transforms them as necessary to pcap_pkthdr headers. Unlike struct pcap_pkthdr , the time stamp in packet headers in a pcap file always have a 32-bit "seconds" field and a 32-bit "microseconds" field, even on systems where time_t and the tv_sec value in a struct timeval are 64 bits.

Ie, the structure is defined by

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) */   
};

where struct pcap_sf_pkthdr is the structure in the file.

Note also that, if you read a struct pcap_sf_pkthdr from a file, you will have to byte-swap ts.tv_sec , ts.tv_usec , caplen , and len IF the file was written on a machine whose byte order differs from the machine on which you're reading the file. Something as simple as ntohl() will NOT work - if, for example, your file was written on the same machine as the one on which you are reading it, no byte-swapping is necessary.

The ONLY way to make that work would be to READ the file header, rather than just skipping over it with fseek() . If the "magic number" in the file header has the value 0xa1b2c3d4 , then you do not need to do any byte swapping; if it has the value 0xd4c3b2a1 , you will need to byte-swap the values in the file header and the struct pcap_sf_pkthdr . Note that ntohl() and htonl() will NOT byte-swap if you're running on a big-endian machine such as a PowerPC/Power Architecture machine or a MIPS machine or an IBM mainframe or....

Note also that not all capture files are going to be pcap files; if they're pcap-NG files, they have to be read in a completely different fashion. Libpcap 1.1 and later know how to read pcap-NG files (the libpcap/WinPcap API isn't powerful enough to handle all pcap-NG files, but it can, for example, handle pcap-NG files that only have one section and only have packets from one network adapter, and libpcap 1.1 and later can read those). I would suggest, just as unwind suggested, that you use libpcap/WinPcap to read capture files, rather than writing your own code to do it.

Make sure that you are correctly handling the endianness of the pcap file format.

Also, directly loading entire structures from disk is rarely safe, since compilers are free to insert padding between structure fields, which will make the bytes from disk not match the bytes in memory.

I would suggest you use the official library, since then those problems will already have been taken care of.

Try something like that:

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM