How can I print whole data of a packet in c?

I'm using libpcap in c to write a packet sniffer. How can I print whole data in the packet? I'v tried this way:

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


void packet_process(u_char *args,const struct pcap_pkthdr *header,const u_char *packet){

        struct ether_header *eh;
        const u_char *ip_header;
        ip_header = packet + 14;
        u_char proto = *(ip_header+9);
        eh=(struct ether_header *) packet;
        const u_char *ptr = packet;
        int bytes = 0;
        char packet_content[1000];
        static int i=0;
        fprintf(stdout, "%d) len: %d\n", ++i, header->len);
        while(bytes ++ < 1000){
                packet_content[bytes-1] = *ptr;
                ptr ++;
        }
        fprintf(stdout, "%s\n\n", packet_content);
        fflush(stdout);

}

int main(int argc, char *argv[]){

    char error[PCAP_ERRBUF_SIZE];
    pcap_t *handle = pcap_open_live(argv[1], BUFSIZ, 0, -2, error);
    pcap_loop(handle, atoi(argv[2]),packet_process, NULL );
    pcap_close(handle);
    return 0;

}

but this code does not show whole data in packet, the output of this code was this:

[amirreza@localhost tmp]$ sudo ./a.out enp3s0 5
1) len: 118
0���:T����

2) len: 145
T����0���:

3) len: 118
0���:T����

4) len: 145
T����0���:

5) len: 117
0���:T����

I don't know how make them human readable and also print whole data in the packet.

2 answers

  • answered 2020-08-04 17:08 Boris Lipschitz

    Don't have pcap here to test it, but i'd start from something really simple, just dump the entire packets, without parsing them, after this part works, proceed with filtering, parsing, etc. Something like this:

    void dump(const void* voidbuf, int len)
    {
        static int linecnt = 16;
        const unsigned char* buf = voidbuf;
        for (int i=0; i<len; i+=linecnt, putch('\n'))
        {
            for (int j=0; j<linecnt; j++, putch(' '))
            {
                static const char HEX[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
                putch(i+j<len ? HEX[buf[i+j] >> 4] : ' ');
                putch(i+j<len ? HEX[buf[i+j] & 0x0F] : ' ');
            }
            putch('|');
            putch(' ');
            for (int j=0; j<linecnt; j++)
                putch(i+j<len ? (buf[i+j]>=' ' && buf[i+j]<='z' ? buf[i+j] : '.') : ' ');
        }
    }
    
    // libpcap callback
    void packet_process(u_char *args,const struct pcap_pkthdr *header,const u_char *packet)
    {
        // just dump the entire thing, after you see this working properly, start working 
        // on filtering just the packets you want, and then, finally, fully parsing the 
        // packets that are out of intereset
        dump(packet, header->caplen);
    }
    

  • answered 2020-08-04 17:35 chux - Reinstate Monica

    At least these issues

    Printing array as string without a null chracter

    Append a null chracter or limit printing.

    Printing unassigned elements of an array

    Limit printing

    Assigning outside array bounds

    Limit assignment loop.

        char packet_content[1000];
        static int i=0;
        fprintf(stdout, "%d) len: %d\n", ++i, header->len);
        int limit = header->len < 1000 ? header->len : 1000;  // add
        //while(bytes ++ < 1000){
        while(bytes ++ < limit){
                packet_content[bytes-1] = *ptr;
                ptr ++;
        }
        // fprintf(stdout, "%s\n\n", packet_content);
        fprintf(stdout, "%.*s\n\n", limit, packet_content);
    

    To print data as hexadecimal

        // fprintf(stdout, "%s\n\n", packet_content);
        for (int i=0; i<limit; i++) {
          fprintf(stdout, " %02X", (unsigned char) packet_content[i]);
          // or since C99
          fprintf(stdout, " %02hhX", packet_content[i]);
          // or best, use unsigned packet_content[1000]
        }
        fprintf(stdout, "\n\n");
    

    To print data as in mixed ASCII and hexadecimal

        for (int i=0; i<limit; i++) {
          unsigned char ch = packet_content[i];
          if (isprint(ch)) {
            fprintf(stdout, " '%c", ch);
          } else {
            fprintf(stdout, " %02X", ch);
          }
        }
        fprintf(stdout, "\n");