0
votes

i have made a packet sniffer using libpcap on C++. I am using pcap_loop and calling a loopback function , which at the moment i havent put much thought of. Here is my code.

int PacketSniff(int *count)
{
   int ifnum;
   int NumOfDevs=0;
   char errbuf[PCAP_ERRBUF_SIZE];
   bpf_u_int32 ip;
   bpf_u_int32  netmask;
   struct in_addr ip_addr , netmask_addr;
   pcap_if_t *devs , *d;
   pcap_t *handler;
   char packet_filter[] = "ip";
   struct bpf_program fcode;


   /* Find all interface devices */
   pcap_findalldevs(&devs, errbuf);

   for(d=devs; d; d=d->next)
   {
       printf("%d. %s", ++NumOfDevs, d->name);
       if (d->description)
       {
           printf(" (%s)\n", d->description);
       }
       else
       {
           printf(" (No description available)\n");
       }
   }
   if(NumOfDevs==0)
   {
       printf("\nNo interfaces found!\n");
       return (-1);
   }


   /* Prompt User to select interface */
   printf("Enter the interface number (1-%d):\n",NumOfDevs);
   scanf("%d",&ifnum);

   if(ifnum < 1 || ifnum > NumOfDevs)
   {
       printf("\nInterface number out of range.\n");
       /* Free the device list */
       pcap_freealldevs(devs);
       return (-1);
   }


   /* Jump to the selected adapter/interface */
   for(d=devs; ifnum>1 ;d=d->next, ifnum--);

   /* Open the selected adapter/interface */
   handler = pcap_open_live(d->name, 65535, 0, 2000, errbuf);

   if ((handler = pcap_open_live(d->name, 65535, 0, 2000, errbuf)) == NULL)
   {
       fprintf(stderr, "Couldn't open device %s: %s\n", d->name, errbuf);
       return(-1);
   }




   if (pcap_datalink(handler) != DLT_EN10MB )
   {
       fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
       pcap_freealldevs(devs);
       return -1;

   }

   /* This means that we set the datalink layer header size at 14 */
   int linkhdrlen = 14;


   if (pcap_lookupnet(d->name, &ip, &netmask, errbuf) <0 )
   {
       fprintf(stderr, "Can't get netmask for device %s\n", d->name);
       netmask = 0;
       ip = 0;
   }


   /* Compile the filter */
   if (pcap_compile(handler, &fcode, packet_filter, 1, netmask) <0 )
   {
       fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.  Error:  %s\n", errbuf);
       pcap_freealldevs(devs);
       return -1;
   }

   /* Set the filter */
   if (pcap_setfilter(handler, &fcode)<0)
   {
       fprintf(stderr,"\nError setting the filter. Error: %s\n", errbuf);
       pcap_freealldevs(devs);
       return -1;
   }


   printf("\nListening for packets on interface <%s>...\n", d->name);

   /* At this point, we don't need any more the device list. Free it */
   pcap_freealldevs(devs);

   pcap_loop(handler, 0, my_callback, NULL);}

And my_callback is like this:

void my_callback(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_ptr){

   struct tm ltime;
   char timestr[16];
   struct ip_header *iphdr;
   struct tcp_header *tcphdr;
   time_t local_tv_sec;




   /* Convert the timestamp to readable format */

   local_tv_sec = header->ts.tv_sec;
   localtime_r(&local_tv_sec , &ltime);
   strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);

   /* Print timestamp and length of the packet */
   printf("Time >> %s.%.6d \nPacket Length:%d \n\n", timestr, header->ts.tv_usec, header->len);

   /* Retireve the position of the ip header    http://www.tcpdump.org/pcap.html */
   iphdr = (ip_header *) (pkt_ptr +14);       




   // Advance to the transport layer header then parse and display
   // the fields based on the type of hearder: tcp, udp or icmp.

   pkt_ptr += 4*iphdr->ver_ihl ;
   tcphdr = (tcp_header *)(pkt_ptr + 14);
   /* print ip addresses and tcp ports */
   printf("%d.%d.%d.%d : %d ---> %d.%d.%d.%d : %d\n\n",
          iphdr->saddr.byte1,
          iphdr->saddr.byte2,
          iphdr->saddr.byte3,
          iphdr->saddr.byte4,
          tcphdr->src_port,
          iphdr->daddr.byte1,
          iphdr->daddr.byte2,
          iphdr->daddr.byte3,
          iphdr->daddr.byte4,
          tcphdr->dst_port);}

Now i can sniff packets and print various things . But my goal is to Extract Stats from the packets (like numOfpackets , numOfTCPpackets , numOfIncomingPAcket , numOfOutgoingPackets , Packet Size Variance , Time Interval Variance ) while they are being sniffed . But i want this to be done in 1000ms Time-Windows.

For example: Every 1000ms i want an output file of..

numOfTCPPackets = ....

numof = ....

.

.

.

My questions are : How can i incorporate those Time-Windows? How to extract the needed stats without interfering too muchwith the sniffing speed.?

Thank you a lot!

1
Your question is a bit broad/unspecific. You actually can track the Time-Window using the callback function accumulating statistical values, and checking the elapsed time, when to output them actually. Kind of passive timer class may be helpful (purposed to calculate the elapsed time since a certain start() or reset() operation).πάντα ῥεῖ
By the way, the code in your question is C code and contains no real C++. I would consider changing the C++ tag to the C tag.juhist

1 Answers

0
votes

Use pcap_next() instead of pcap_loop() to get the packet and set the timeout with pcap_set_timeout() to a small value such as 10 milliseconds to prevent pcap_next() blocking forever so that your code to write the statistics to the file gets a chance to run. You need to call pcap_next() in a loop and have code like the following after the pcap_next() call:

if (cur_time64() - last_time64 >= stat_time64)
{
    last_time64 += stat_time64;
    print_statistics_to_file();
}

...where cur_time64() returns the current time as a 64-bit integer in microseconds since the epoch (you can use gettimeofday() to implement cur_time64() if you use a Unix-like operating system). stat_time64 would be 1 second, i.e. 1000*1000, in your example.

Then, proceed to process the packet. Check the return value of pcap_next() to see if it returned a packet: if no, continue the loop; if yes, process the packet.

To do the checks without interfering too much with the sniffing speed, your only option is to write the code as efficiently as possible. Handle only those header fields you absolutely need to handle, i.e. you can avoid checking the checksums of IP and TCP headers.