2
votes

I want to write a small application using Libpcap in C on Linux.

Currently, it starts to sniff and wait for the packets. But that's not what I need actually. I want it to wait for N seconds and then stop listening.

How can I achieve that?

Here is my code:

void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
       printf("got packet\n);
}

int main()
{
 int ret = 0;
 char *dev = NULL;   /* capture device name */
 char errbuf[PCAP_ERRBUF_SIZE];  /* error buffer */
 pcap_t *handle;    /* packet capture handle */

 char filter_exp[] = "udp dst port 1500";  /* filter expression */
 struct bpf_program fp;   /* compiled filter program (expression) */
 bpf_u_int32 mask;   /* subnet mask */
 bpf_u_int32 net;   /* ip */
 int num_packets = 10;   /* number of packets to capture */


 /* get network number and mask associated with capture device */
 if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
  fprintf(stderr, "Couldn't get netmask for device %s: %s\n",
      dev, errbuf);
  net = 0;
  mask = 0;
 }


 /* print capture info */
 printf("Device: %s\n", dev);
 printf("Number of packets: %d\n", num_packets);
 printf("Filter expression: %s\n", filter_exp);




 /* open capture device */
 handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);
 if (handle == NULL) {
  fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
  exit(EXIT_FAILURE);
 }



 /* compile the filter expression */
 if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
  fprintf(stderr, "Couldn't parse filter %s: %s\n",
      filter_exp, pcap_geterr(handle));
  exit(EXIT_FAILURE);
 }

 /* apply the compiled filter */
 if (pcap_setfilter(handle, &fp) == -1) {
  fprintf(stderr, "Couldn't install filter %s: %s\n",
      filter_exp, pcap_geterr(handle));
  exit(EXIT_FAILURE);
 }

 /* now we can set our callback function */
 pcap_loop(handle, num_packets, got_packet, NULL);

 /* cleanup */
 pcap_freecode(&fp);
 pcap_close(handle);
}
4

4 Answers

7
votes

You should call pcap_breakloop() when you want stop listening. So one way would be to:

  • setup an alarm to trigger in N seconds,
  • install a signal handler for SIGALRM signal,
  • call pcap_breakloop() inside the handler to make pcap_loop() return.

code:

void alarm_handler(int sig)
{
    pcap_breakloop(handle);
}

int main()
{
    ...

    alarm(N);
    signal(SIGALRM, alarm_handler);

    /* now we can set our callback function */
    pcap_loop(handle, num_packets, got_packet, NULL);

    /* cleanup */
    pcap_freecode(&fp);
    pcap_close(handle);
}

Note: As for using libpcap's read timeout to do this, it won't and can't work, man pcap explicitly warns against it:

The read timeout cannot be used to cause calls that read packets to return within a limited period of time [...] This means that the read timeout should NOT be used, for example, in an interactive application to allow the packet capture loop to poll for user input periodically, as there's no guarantee that a call reading packets will return after the timeout expires even if no packets have arrived.

2
votes

If you look at this page from the tcpdump website, you can see the follwing:

Opening the device for sniffing

The task of creating a sniffing session is really quite simple. For this, we use pcap_open_live(). The prototype of this function (from the pcap man page) is as follows:

pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms,
                       char *ebuf)

The first argument is the device that we specified in the previous section. snaplen is an integer which defines the maximum number of bytes to be captured by pcap. promisc, when set to true, brings the interface into promiscuous mode (however, even if it is set to false, it is possible under specific cases for the interface to be in promiscuous mode, anyway). to_ms is the read time out in milliseconds (a value of 0 means no time out; on at least some platforms, this means that you may wait until a sufficient number of packets arrive before seeing any packets, so you should use a non-zero timeout). Lastly, ebuf is a string we can store any error messages within (as we did above with errbuf). The function returns our session handler.

If this does not work, let us know.

0
votes

I have been studying and testing these code fragments for a while. Somewhere, I noticed the observation that when you exit pcap_loop, although you may have seen packets, the exit conditions suggest that you have seen none. I assume from this that all the processing of the packet must occur in the scope of the callback function. So if I want to reset quickly and be ready for another packet, I will need to spawn another process to work on each packet.

0
votes

Old post but I was researching and came across this.

From the man page for pcap_loop() it specifically says, "It does not return when live read timeouts occur; instead, it attempts to read more packets."

But the man pages for pcap_dispatch() and pcap_next() both indicate they return on timeout.