The callback-based capture mechanism of pcap_loop() is elegant and it could be a good choice in some situations. However, handling a callback is sometimes not practical -- it often makes the program more complex especially in situations with multithreaded applications or C++ classes.
In these cases, pcap_next_ex() retrievs a packet with a direct call -- using pcap_next_ex() packets are received only when the programmer wants them.
The parameters of this function are the same as a capture callback -- it takes an adapter descriptor and a couple of pointers that will be initialized and returned to the user (one to a pcap_pkthdr structure and another to a buffer with the packet data).
In the following program, we recycle the callback code of the previous lesson's example and move it inside main() right after the call to pcap_next_ex().
#include "pcap.h" main() { pcap_if_t *alldevs; pcap_if_t *d; int inum; int i=0; pcap_t *adhandle; int res; char errbuf[PCAP_ERRBUF_SIZE]; struct tm *ltime; char timestr[16]; struct pcap_pkthdr *header; const u_char *pkt_data; time_t local_tv_sec; /* Retrieve the device list on the local machine */ if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); exit(1); } /* Print the list */ for(d=alldevs; d; d=d->next) { printf("%d. %s", ++i, d->name); if (d->description) printf(" (%s)\n", d->description); else printf(" (No description available)\n"); } if(i==0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return -1; } printf("Enter the interface number (1-%d):",i); scanf("%d", &inum); if(inum < 1 || inum > i) { printf("\nInterface number out of range.\n"); /* Free the device list */ pcap_freealldevs(alldevs); return -1; } /* Jump to the selected adapter */ for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); /* Open the device */ if ( (adhandle= pcap_open(d->name, // name of the device 65536, // portion of the packet to capture. // 65536 guarantees that the whole packet will be captured on all the link layers PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode 1000, // read timeout NULL, // authentication on the remote machine errbuf // error buffer ) ) == NULL) { fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); /* Free the device list */ pcap_freealldevs(alldevs); return -1; } printf("\nlistening on %s...\n", d->description); /* At this point, we don't need any more the device list. Free it */ pcap_freealldevs(alldevs); /* Retrieve the packets */ while((res = pcap_next_ex( adhandle, &header, &pkt_data)) >= 0){ if(res == 0) /* Timeout elapsed */ continue; /* convert the timestamp to readable format */ local_tv_sec = header->ts.tv_sec; ltime=localtime(&local_tv_sec); strftime( timestr, sizeof timestr, "%H:%M:%S", ltime); printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len); } if(res == -1){ printf("Error reading the packets: %s\n", pcap_geterr(adhandle)); return -1; } return 0; }
00001 #include "pcap.h" 00002 00003 00004 main() 00005 { 00006 pcap_if_t *alldevs; 00007 pcap_if_t *d; 00008 int inum; 00009 int i=0; 00010 pcap_t *adhandle; 00011 int res; 00012 char errbuf[PCAP_ERRBUF_SIZE]; 00013 struct tm *ltime; 00014 char timestr[16]; 00015 struct pcap_pkthdr *header; 00016 const u_char *pkt_data; 00017 time_t local_tv_sec; 00018 00019 00020 /* Retrieve the device list on the local machine */ 00021 if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) 00022 { 00023 fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); 00024 exit(1); 00025 } 00026 00027 /* Print the list */ 00028 for(d=alldevs; d; d=d->next) 00029 { 00030 printf("%d. %s", ++i, d->name); 00031 if (d->description) 00032 printf(" (%s)\n", d->description); 00033 else 00034 printf(" (No description available)\n"); 00035 } 00036 00037 if(i==0) 00038 { 00039 printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); 00040 return -1; 00041 } 00042 00043 printf("Enter the interface number (1-%d):",i); 00044 scanf("%d", &inum); 00045 00046 if(inum < 1 || inum > i) 00047 { 00048 printf("\nInterface number out of range.\n"); 00049 /* Free the device list */ 00050 pcap_freealldevs(alldevs); 00051 return -1; 00052 } 00053 00054 /* Jump to the selected adapter */ 00055 for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); 00056 00057 /* Open the device */ 00058 if ( (adhandle= pcap_open(d->name, // name of the device 00059 65536, // portion of the packet to capture. 00060 // 65536 guarantees that the whole packet will be captured on all the link layers 00061 PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode 00062 1000, // read timeout 00063 NULL, // authentication on the remote machine 00064 errbuf // error buffer 00065 ) ) == NULL) 00066 { 00067 fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); 00068 /* Free the device list */ 00069 pcap_freealldevs(alldevs); 00070 return -1; 00071 } 00072 00073 printf("\nlistening on %s...\n", d->description); 00074 00075 /* At this point, we don't need any more the device list. Free it */ 00076 pcap_freealldevs(alldevs); 00077 00078 /* Retrieve the packets */ 00079 while((res = pcap_next_ex( adhandle, &header, &pkt_data)) >= 0){ 00080 00081 if(res == 0) 00082 /* Timeout elapsed */ 00083 continue; 00084 00085 /* convert the timestamp to readable format */ 00086 local_tv_sec = header->ts.tv_sec; 00087 ltime=localtime(&local_tv_sec); 00088 strftime( timestr, sizeof timestr, "%H:%M:%S", ltime); 00089 00090 printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len); 00091 } 00092 00093 if(res == -1){ 00094 printf("Error reading the packets: %s\n", pcap_geterr(adhandle)); 00095 return -1; 00096 } 00097 00098 return 0; 00099 }
Why do we use pcap_next_ex() instead of the old pcap_next()? Because pcap_next() has some drawbacks. First of all, it is inefficient because it hides the callback method but still relies on pcap_dispatch(). Second, it is not able to detect EOF, so it's not very useful when gathering packets from a file.
Notice also that pcap_next_ex() returns different values for success, timeout elapsed, error and EOF conditions.
documentation. Copyright (c) 2002-2005 Politecnico di Torino. Copyright (c) 2005-2006
CACE Technologies. All rights reserved.