Search code examples
cnetwork-programmingendiannesstcpdump

Read libcap file with specific endianness


I wrote a c-lang program to read a .pcap file.What fogs me is that the data I read was with a different endianness as to WireShark.

I'm working on X86 ach, as I can see, it's LittleEndian.

So, can I read the .pcap file with BigEndian? How?

Code fragments:

/*
 * global header
 */
typedef struct{
    // fileds here
} GlobalHdr;

/*
 * record (packet) header
 */
typedef struct{
    // fileds here
} RecordHdr;

/*
 * IP v4 header
 */
typedef struct{
    // fileds here
    /* the options start here, if tot_len is bigger than 5*/
} Ipv4Hdr;

/*
 * UDP header
 */
typedef struct{
    // fileds here
} UdpHdr;


/*
 * main function
 */
int main(){
    FILE *srcfile = NULL; // the .pcap file
    GlobalHdr g_hdr = {0};
    RecordHdr r_hdr = {0};
    Ipv4Hdr ip_hdr = {0};
    UdpHdr u_hdr  = {0};
    unsigned long fl_len = 0;
    unsigned long index = 0;
    unsigned char sizghdr = sizeof(GlobalHdr);
    unsigned char sizrhdr = sizeof(RecordHdr);
    unsigned char sizihdr = sizeof(Ipv4Hdr);
    unsigned char sizuhdr = sizeof(UdpHdr);

    srcfile = fopen (SRC_FILE, "r");
    if(!srcfile){
        PERR ("source file opening");
    }

    fseek (srcfile, 0, SEEK_END);
    fl_len = ftell (srcfile);
    fseek (srcfile, 0, SEEK_SET);
    printf ("file length: %ld\n", fl_len);

    // read file global header

    CHECK_POSITION (sizghdr);
    if(!fread (&g_hdr, sizghdr, 1, srcfile)){
        PERR ("reading global header");
    }
    print_ghdr (&g_hdr);

    // read blocks

    while(1){
        // read block header
        CHECK_POSITION (sizrhdr);
        if(!fread (&r_hdr, sizrhdr, 1, srcfile)){
            PERR ("reading block header");
        }
        print_rhdr (&r_hdr);

        // read ethernet header
        CHECK_POSITION (LINK_LAYER_LEN);
        fseek (srcfile, index, SEEK_SET);

        // read IP header
        CHECK_POSITION (sizihdr);
        if(!fread (&ip_hdr, sizihdr, 1, srcfile)){
            PERR ("reading ip header");
        }
        print_iphdr (&ip_hdr);

        // read UDP header
        CHECK_POSITION (sizuhdr);
        if(!fread (&u_hdr, sizuhdr, 1, srcfile)){
            PERR ("reading upd header");
        }
        print_udphdr (&u_hdr);

        // read contained data
        CHECK_POSITION (r_hdr.orig_len - sizrhdr
                - LINK_LAYER_LEN - sizihdr - sizuhdr
                );
        fseek (srcfile, index, SEEK_SET);
    }

    // clean up

    puts ("Done!");
    CLEAN_UP;
    return 0;
}

Solution

  • So, can I read the .pcap file with BigEndian?

    Yes.

    How?

    1. use libpcap/WinPcap, rather than writing your own code to read it, as libpcap/WinPcap handles byte-order issues for you;
    2. look at the magic number to determine whether the file is in the same byte order as the host reading it or the opposite byte order and, if it's in the opposite byte order, byte-swap the 16-bit and 32-bit integral quantities.

    Note that the packet data is (except for some metadata headers, such as USB metadata) in the byte order in which it appears on the network, not the byte order of the host writing the data. For example, 16-bit and 32-bit integral values in IP and TCP headers are always big-endian, as is the Ethernet type field.